// Internally, only Feature additions/removals are stored for each layer. If a layer has a parent, // the Feature list will be compared to the parent's Feature list and the difference will be stored. // Note that when the Namespace of a layer differs from its parent, it is expected that several // Feature that were already included a parent will have their Namespace updated as well // (happens when Feature detectors relies on the detected layer Namespace). However, if the listed // Feature has the same Name/Version as its parent, InsertLayer considers that the Feature hasn't // been modified. func (pgSQL *pgSQL) InsertLayer(layer database.Layer) error { tf := time.Now() // Verify parameters if layer.Name == "" { log.Warning("could not insert a layer which has an empty Name") return cerrors.NewBadRequestError("could not insert a layer which has an empty Name") } // Get a potentially existing layer. existingLayer, err := pgSQL.FindLayer(layer.Name, true, false) if err != nil && err != cerrors.ErrNotFound { return err } else if err == nil { if existingLayer.EngineVersion >= layer.EngineVersion { // The layer exists and has an equal or higher engine version, do nothing. return nil } layer.ID = existingLayer.ID } // We do `defer observeQueryTime` here because we don't want to observe existing layers. defer observeQueryTime("InsertLayer", "all", tf) // Get parent ID. var parentID zero.Int if layer.Parent != nil { if layer.Parent.ID == 0 { log.Warning("Parent is expected to be retrieved from database when inserting a layer.") return cerrors.NewBadRequestError("Parent is expected to be retrieved from database when inserting a layer.") } parentID = zero.IntFrom(int64(layer.Parent.ID)) } // Find or insert namespace if provided. var namespaceID zero.Int if layer.Namespace != nil { n, err := pgSQL.insertNamespace(*layer.Namespace) if err != nil { return err } namespaceID = zero.IntFrom(int64(n)) } else if layer.Namespace == nil && layer.Parent != nil { // Import the Namespace from the parent if it has one and this layer doesn't specify one. if layer.Parent.Namespace != nil { namespaceID = zero.IntFrom(int64(layer.Parent.Namespace.ID)) } } // Begin transaction. tx, err := pgSQL.Begin() if err != nil { tx.Rollback() return handleError("InsertLayer.Begin()", err) } if layer.ID == 0 { // Insert a new layer. err = tx.QueryRow(insertLayer, layer.Name, layer.EngineVersion, parentID, namespaceID). Scan(&layer.ID) if err != nil { tx.Rollback() if isErrUniqueViolation(err) { // Ignore this error, another process collided. log.Debug("Attempted to insert duplicate layer.") return nil } return handleError("insertLayer", err) } } else { // Update an existing layer. _, err = tx.Exec(updateLayer, layer.ID, layer.EngineVersion, namespaceID) if err != nil { tx.Rollback() return handleError("updateLayer", err) } // Remove all existing Layer_diff_FeatureVersion. _, err = tx.Exec(removeLayerDiffFeatureVersion, layer.ID) if err != nil { tx.Rollback() return handleError("removeLayerDiffFeatureVersion", err) } } // Update Layer_diff_FeatureVersion now. err = pgSQL.updateDiffFeatureVersions(tx, &layer, &existingLayer) if err != nil { tx.Rollback() return err } // Commit transaction. err = tx.Commit() if err != nil { tx.Rollback() return handleError("InsertLayer.Commit()", err) } return nil }