+static int
+check_real_range(double x)
+{
+ return x >= -DBL_MAX && x <= DBL_MAX ? 0 : ME_RANGE;
+}
+
+static struct ovsdb_error *
+mutate_scalar(const struct ovsdb_type *dst_type, struct ovsdb_datum *dst,
+ const union ovsdb_atom *arg,
+ const struct ovsdb_scalar_mutation *mutation)
+{
+ const struct ovsdb_base_type *base = &dst_type->key;
+ struct ovsdb_error *error;
+ unsigned int i;
+
+ if (base->type == OVSDB_TYPE_INTEGER) {
+ int64_t y = arg->integer;
+ for (i = 0; i < dst->n; i++) {
+ enum ovsdb_mutation_scalar_error me;
+
+ me = (mutation->mutate_integer)(&dst->keys[i].integer, y);
+ if (me != ME_OK) {
+ return ovsdb_mutation_scalar_error(me, mutation->mutator);
+ }
+ }
+ } else if (base->type == OVSDB_TYPE_REAL) {
+ double y = arg->real;
+ for (i = 0; i < dst->n; i++) {
+ double *x = &dst->keys[i].real;
+ enum ovsdb_mutation_scalar_error me;
+
+ me = (mutation->mutate_real)(x, y);
+ if (me == ME_OK) {
+ me = check_real_range(*x);
+ }
+ if (me != ME_OK) {
+ return ovsdb_mutation_scalar_error(me, mutation->mutator);
+ }
+ }
+ } else {
+ NOT_REACHED();
+ }
+
+ for (i = 0; i < dst->n; i++) {
+ error = ovsdb_atom_check_constraints(&dst->keys[i], base);
+ if (error) {
+ return error;
+ }
+ }
+
+ error = ovsdb_datum_sort(dst, dst_type->key.type);
+ if (error) {
+ ovsdb_error_destroy(error);
+ return ovsdb_error("constraint violation",
+ "Result of \"%s\" operation contains duplicates.",
+ ovsdb_mutator_to_string(mutation->mutator));
+ }
+ return NULL;
+}
+
+static struct ovsdb_error *
+ovsdb_mutation_check_count(struct ovsdb_datum *dst,
+ const struct ovsdb_type *dst_type)
+{
+ if (!ovsdb_datum_conforms_to_type(dst, dst_type)) {
+ char *s = ovsdb_type_to_english(dst_type);
+ struct ovsdb_error *e = ovsdb_error(
+ "constaint violation",
+ "Attempted to store %u elements in %s.", dst->n, s);
+ free(s);
+ return e;
+ }
+ return NULL;
+}
+
+struct ovsdb_error *
+ovsdb_mutation_set_execute(struct ovsdb_row *row,
+ const struct ovsdb_mutation_set *set)
+{
+ size_t i;
+
+ for (i = 0; i < set->n_mutations; i++) {
+ const struct ovsdb_mutation *m = &set->mutations[i];
+ struct ovsdb_datum *dst = &row->fields[m->column->index];
+ const struct ovsdb_type *dst_type = &m->column->type;
+ const struct ovsdb_datum *arg = &set->mutations[i].arg;
+ const struct ovsdb_type *arg_type = &m->type;
+ struct ovsdb_error *error;
+
+ switch (m->mutator) {
+ case OVSDB_M_ADD:
+ error = mutate_scalar(dst_type, dst, &arg->keys[0], &add_mutation);
+ break;
+
+ case OVSDB_M_SUB:
+ error = mutate_scalar(dst_type, dst, &arg->keys[0], &sub_mutation);
+ break;
+
+ case OVSDB_M_MUL:
+ error = mutate_scalar(dst_type, dst, &arg->keys[0], &mul_mutation);
+ break;
+
+ case OVSDB_M_DIV:
+ error = mutate_scalar(dst_type, dst, &arg->keys[0], &div_mutation);
+ break;
+
+ case OVSDB_M_MOD:
+ error = mutate_scalar(dst_type, dst, &arg->keys[0], &mod_mutation);
+ break;
+
+ case OVSDB_M_INSERT:
+ ovsdb_datum_union(dst, arg, dst_type, false);
+ error = ovsdb_mutation_check_count(dst, dst_type);
+ break;
+
+ case OVSDB_M_DELETE:
+ ovsdb_datum_subtract(dst, dst_type, arg, arg_type);
+ error = ovsdb_mutation_check_count(dst, dst_type);
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+ if (error) {
+ return error;
+ }
+ }
+
+ return NULL;
+}
+\f