X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ovsdb%2Fmutation.c;h=967ad157d0cdbc819753f9b6aa0289538e1cc747;hb=HEAD;hp=53e46f93006e7f1256459993b5b8be76e671167a;hpb=2f47998baea215b996af0be4d1653032005e3ac4;p=sliver-openvswitch.git diff --git a/ovsdb/mutation.c b/ovsdb/mutation.c index 53e46f930..967ad157d 100644 --- a/ovsdb/mutation.c +++ b/ovsdb/mutation.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2010 Nicira Networks +/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,14 +26,6 @@ #include "row.h" #include "table.h" -enum mutate_error { - ME_OK, - ME_DOM, - ME_RANGE, - ME_COUNT, - ME_DUP -}; - struct ovsdb_error * ovsdb_mutator_from_string(const char *name, enum ovsdb_mutator *mutator) { @@ -80,7 +72,7 @@ type_mismatch(const struct ovsdb_mutation *m, const struct json *json) static WARN_UNUSED_RESULT struct ovsdb_error * ovsdb_mutation_from_json(const struct ovsdb_table_schema *ts, const struct json *json, - const struct ovsdb_symbol_table *symtab, + struct ovsdb_symbol_table *symtab, struct ovsdb_mutation *m) { const struct json_array *array; @@ -103,12 +95,18 @@ ovsdb_mutation_from_json(const struct ovsdb_table_schema *ts, "No column %s in table %s.", column_name, ts->name); } - m->type = m->column->type; + if (!m->column->mutable) { + return ovsdb_syntax_error(json, "constraint violation", + "Cannot mutate immutable column %s in " + "table %s.", column_name, ts->name); + } + + ovsdb_type_clone(&m->type, &m->column->type); mutator_name = json_string(array->elems[1]); error = ovsdb_mutator_from_string(mutator_name, &m->mutator); if (error) { - return error; + goto exit; } /* Type-check and relax restrictions on 'type' if appropriate. */ @@ -119,15 +117,17 @@ ovsdb_mutation_from_json(const struct ovsdb_table_schema *ts, case OVSDB_M_DIV: case OVSDB_M_MOD: if ((!ovsdb_type_is_scalar(&m->type) && !ovsdb_type_is_set(&m->type)) - || (m->type.key_type != OVSDB_TYPE_INTEGER - && m->type.key_type != OVSDB_TYPE_REAL) + || (m->type.key.type != OVSDB_TYPE_INTEGER + && m->type.key.type != OVSDB_TYPE_REAL) || (m->mutator == OVSDB_M_MOD - && m->type.key_type == OVSDB_TYPE_REAL)) { + && m->type.key.type == OVSDB_TYPE_REAL)) { return type_mismatch(m, json); } + ovsdb_base_type_clear_constraints(&m->type.key); m->type.n_min = m->type.n_max = 1; - return ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2], - symtab); + error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2], + symtab); + break; case OVSDB_M_INSERT: case OVSDB_M_DELETE: @@ -143,26 +143,34 @@ ovsdb_mutation_from_json(const struct ovsdb_table_schema *ts, if (error && ovsdb_type_is_map(&m->type) && m->mutator == OVSDB_M_DELETE) { ovsdb_error_destroy(error); - m->type.value_type = OVSDB_TYPE_VOID; + m->type.value.type = OVSDB_TYPE_VOID; error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2], symtab); } - return error; + break; + + default: + OVS_NOT_REACHED(); } - NOT_REACHED(); +exit: + if (error) { + ovsdb_type_destroy(&m->type); + } + return error; } static void ovsdb_mutation_free(struct ovsdb_mutation *m) { ovsdb_datum_destroy(&m->arg, &m->type); + ovsdb_type_destroy(&m->type); } struct ovsdb_error * ovsdb_mutation_set_from_json(const struct ovsdb_table_schema *ts, const struct json *json, - const struct ovsdb_symbol_table *symtab, + struct ovsdb_symbol_table *symtab, struct ovsdb_mutation_set *set) { const struct json_array *array = json_array(json); @@ -218,7 +226,177 @@ ovsdb_mutation_set_destroy(struct ovsdb_mutation_set *set) } free(set->mutations); } + +enum ovsdb_mutation_scalar_error { + ME_OK, + ME_DOM, + ME_RANGE +}; + +struct ovsdb_scalar_mutation { + int (*mutate_integer)(int64_t *x, int64_t y); + int (*mutate_real)(double *x, double y); + enum ovsdb_mutator mutator; +}; + +static const struct ovsdb_scalar_mutation add_mutation; +static const struct ovsdb_scalar_mutation sub_mutation; +static const struct ovsdb_scalar_mutation mul_mutation; +static const struct ovsdb_scalar_mutation div_mutation; +static const struct ovsdb_scalar_mutation mod_mutation; + +static struct ovsdb_error * +ovsdb_mutation_scalar_error(enum ovsdb_mutation_scalar_error error, + enum ovsdb_mutator mutator) +{ + switch (error) { + case ME_OK: + return OVSDB_BUG("unexpected success"); + + case ME_DOM: + return ovsdb_error("domain error", "Division by zero."); + + case ME_RANGE: + return ovsdb_error("range error", + "Result of \"%s\" operation is out of range.", + ovsdb_mutator_to_string(mutator)); + + default: + return OVSDB_BUG("unexpected error"); + } +} + +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 { + OVS_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( + "constraint 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: + OVS_NOT_REACHED(); + } + if (error) { + return error; + } + } + + return NULL; +} + static int add_int(int64_t *x, int64_t y) { @@ -296,12 +474,6 @@ mod_int(int64_t *x, int64_t y) return error; } -static int -check_real_range(double x) -{ - return x >= -DBL_MAX && x <= DBL_MAX ? 0 : ME_RANGE; -} - static int add_double(double *x, double y) { @@ -334,129 +506,22 @@ div_double(double *x, double y) } } -static int -mutate_scalar(const struct ovsdb_type *dst_type, struct ovsdb_datum *dst, - const union ovsdb_atom *arg, - int (*mutate_integer)(int64_t *x, int64_t y), - int (*mutate_real)(double *x, double y)) -{ - struct ovsdb_error *error; - unsigned int i; - - if (dst_type->key_type == OVSDB_TYPE_INTEGER) { - int64_t y = arg->integer; - for (i = 0; i < dst->n; i++) { - int error = mutate_integer(&dst->keys[i].integer, y); - if (error) { - return error; - } - } - } else if (dst_type->key_type == OVSDB_TYPE_REAL) { - double y = arg->real; - for (i = 0; i < dst->n; i++) { - double *x = &dst->keys[i].real; - int error = mutate_real(x, y); - if (!error) { - error = check_real_range(*x); - } - if (error) { - return error; - } - } - } else { - NOT_REACHED(); - } - - error = ovsdb_datum_sort(dst, dst_type); - if (error) { - ovsdb_error_destroy(error); - return ME_DUP; - } - return 0; -} - -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; - int error; - - switch (m->mutator) { - case OVSDB_M_ADD: - error = mutate_scalar(dst_type, dst, &arg->keys[0], - add_int, add_double); - break; - - case OVSDB_M_SUB: - error = mutate_scalar(dst_type, dst, &arg->keys[0], - sub_int, sub_double); - break; - - case OVSDB_M_MUL: - error = mutate_scalar(dst_type, dst, &arg->keys[0], - mul_int, mul_double); - break; - - case OVSDB_M_DIV: - error = mutate_scalar(dst_type, dst, &arg->keys[0], - div_int, div_double); - break; - - case OVSDB_M_MOD: - error = mutate_scalar(dst_type, dst, &arg->keys[0], - mod_int, NULL); - break; - - case OVSDB_M_INSERT: - ovsdb_datum_union(dst, arg, dst_type, false); - error = ovsdb_datum_conforms_to_type(dst, dst_type) ? 0 : ME_COUNT; - break; - - case OVSDB_M_DELETE: - ovsdb_datum_subtract(dst, dst_type, arg, arg_type); - error = ovsdb_datum_conforms_to_type(dst, dst_type) ? 0 : ME_COUNT; - break; - } +static const struct ovsdb_scalar_mutation add_mutation = { + add_int, add_double, OVSDB_M_ADD +}; - switch (error) { - case 0: - break; +static const struct ovsdb_scalar_mutation sub_mutation = { + sub_int, sub_double, OVSDB_M_SUB +}; - case ME_DOM: - return ovsdb_error("domain error", "Division by zero."); - - case ME_RANGE: - return ovsdb_error("range error", - "Result of \"%s\" operation is out of range.", - ovsdb_mutator_to_string(m->mutator)); - - case ME_DUP: - return ovsdb_error("constraint violation", - "Result of \"%s\" operation contains " - "duplicates.", - ovsdb_mutator_to_string(m->mutator)); - - case ME_COUNT: { - 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; - } +static const struct ovsdb_scalar_mutation mul_mutation = { + mul_int, mul_double, OVSDB_M_MUL +}; - default: - return OVSDB_BUG("unexpected errno"); - } - } +static const struct ovsdb_scalar_mutation div_mutation = { + div_int, div_double, OVSDB_M_DIV +}; - return NULL; -} +static const struct ovsdb_scalar_mutation mod_mutation = { + mod_int, NULL, OVSDB_M_MOD +};