]> git.proxmox.com Git - mirror_ovs.git/blame - ovsdb/mutation.c
dist-docs: Include manpages generated from rST.
[mirror_ovs.git] / ovsdb / mutation.c
CommitLineData
341c4e59 1/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
e9f8f936
BP
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <config.h>
17
18#include "mutation.h"
19
20#include <float.h>
21#include <limits.h>
22
23#include "column.h"
24#include "ovsdb-error.h"
ee89ea7b 25#include "openvswitch/json.h"
e9f8f936 26#include "row.h"
ee89ea7b
TW
27
28#include <string.h>
29
e9f8f936 30#include "table.h"
ee89ea7b 31#include "util.h"
e9f8f936 32
e9f8f936
BP
33struct ovsdb_error *
34ovsdb_mutator_from_string(const char *name, enum ovsdb_mutator *mutator)
35{
36#define OVSDB_MUTATOR(ENUM, NAME) \
37 if (!strcmp(name, NAME)) { \
38 *mutator = ENUM; \
39 return NULL; \
40 }
41 OVSDB_MUTATORS;
42#undef OVSDB_MUTATOR
43
44 return ovsdb_syntax_error(NULL, "unknown mutator",
45 "No mutator named %s.", name);
46}
47
48const char *
49ovsdb_mutator_to_string(enum ovsdb_mutator mutator)
50{
51 switch (mutator) {
52#define OVSDB_MUTATOR(ENUM, NAME) case ENUM: return NAME;
53 OVSDB_MUTATORS;
54#undef OVSDB_MUTATOR
55 }
56
57 return NULL;
58}
59
cab50449 60static OVS_WARN_UNUSED_RESULT struct ovsdb_error *
e9f8f936
BP
61type_mismatch(const struct ovsdb_mutation *m, const struct json *json)
62{
63 struct ovsdb_error *error;
64 char *s;
65
66 s = ovsdb_type_to_english(&m->column->type);
67 error = ovsdb_syntax_error(
68 json, NULL, "Type mismatch: \"%s\" operator may not be "
69 "applied to column %s of type %s.",
70 ovsdb_mutator_to_string(m->mutator), m->column->name, s);
71 free(s);
72
73 return error;
74}
75
cab50449 76static OVS_WARN_UNUSED_RESULT struct ovsdb_error *
e9f8f936
BP
77ovsdb_mutation_from_json(const struct ovsdb_table_schema *ts,
78 const struct json *json,
fbf925e4 79 struct ovsdb_symbol_table *symtab,
e9f8f936
BP
80 struct ovsdb_mutation *m)
81{
82 const struct json_array *array;
83 struct ovsdb_error *error;
84 const char *mutator_name;
85 const char *column_name;
86
87 if (json->type != JSON_ARRAY
fa37affa
BP
88 || json->array.n != 3
89 || json->array.elems[0]->type != JSON_STRING
90 || json->array.elems[1]->type != JSON_STRING) {
e9f8f936
BP
91 return ovsdb_syntax_error(json, NULL, "Parse error in mutation.");
92 }
93 array = json_array(json);
94
95 column_name = json_string(array->elems[0]);
96 m->column = ovsdb_table_schema_get_column(ts, column_name);
97 if (!m->column) {
98 return ovsdb_syntax_error(json, "unknown column",
99 "No column %s in table %s.",
100 column_name, ts->name);
101 }
341c4e59
BP
102 if (!m->column->mutable) {
103 return ovsdb_syntax_error(json, "constraint violation",
104 "Cannot mutate immutable column %s in "
105 "table %s.", column_name, ts->name);
106 }
107
bd76d25d 108 ovsdb_type_clone(&m->type, &m->column->type);
e9f8f936
BP
109
110 mutator_name = json_string(array->elems[1]);
111 error = ovsdb_mutator_from_string(mutator_name, &m->mutator);
112 if (error) {
bd76d25d 113 goto exit;
e9f8f936
BP
114 }
115
116 /* Type-check and relax restrictions on 'type' if appropriate. */
117 switch (m->mutator) {
118 case OVSDB_M_ADD:
119 case OVSDB_M_SUB:
120 case OVSDB_M_MUL:
121 case OVSDB_M_DIV:
122 case OVSDB_M_MOD:
123 if ((!ovsdb_type_is_scalar(&m->type) && !ovsdb_type_is_set(&m->type))
bd76d25d
BP
124 || (m->type.key.type != OVSDB_TYPE_INTEGER
125 && m->type.key.type != OVSDB_TYPE_REAL)
e9f8f936 126 || (m->mutator == OVSDB_M_MOD
bd76d25d 127 && m->type.key.type == OVSDB_TYPE_REAL)) {
e9f8f936
BP
128 return type_mismatch(m, json);
129 }
bd76d25d 130 ovsdb_base_type_clear_constraints(&m->type.key);
e9f8f936 131 m->type.n_min = m->type.n_max = 1;
bd76d25d
BP
132 error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
133 symtab);
134 break;
e9f8f936
BP
135
136 case OVSDB_M_INSERT:
137 case OVSDB_M_DELETE:
138 if (!ovsdb_type_is_set(&m->type) && !ovsdb_type_is_map(&m->type)) {
139 return type_mismatch(m, json);
140 }
141 m->type.n_min = 0;
142 if (m->mutator == OVSDB_M_DELETE) {
143 m->type.n_max = UINT_MAX;
144 }
145 error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
146 symtab);
147 if (error && ovsdb_type_is_map(&m->type)
148 && m->mutator == OVSDB_M_DELETE) {
149 ovsdb_error_destroy(error);
acb691e1
DS
150 ovsdb_base_type_destroy(&m->type.value);
151 m->type.value.enum_ = NULL;
bd76d25d 152 m->type.value.type = OVSDB_TYPE_VOID;
e9f8f936
BP
153 error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
154 symtab);
155 }
bd76d25d
BP
156 break;
157
158 default:
428b2edd 159 OVS_NOT_REACHED();
e9f8f936
BP
160 }
161
bd76d25d
BP
162exit:
163 if (error) {
164 ovsdb_type_destroy(&m->type);
165 }
166 return error;
e9f8f936
BP
167}
168
169static void
170ovsdb_mutation_free(struct ovsdb_mutation *m)
171{
172 ovsdb_datum_destroy(&m->arg, &m->type);
bd76d25d 173 ovsdb_type_destroy(&m->type);
e9f8f936
BP
174}
175
176struct ovsdb_error *
177ovsdb_mutation_set_from_json(const struct ovsdb_table_schema *ts,
178 const struct json *json,
fbf925e4 179 struct ovsdb_symbol_table *symtab,
e9f8f936
BP
180 struct ovsdb_mutation_set *set)
181{
182 const struct json_array *array = json_array(json);
183 size_t i;
184
185 set->mutations = xmalloc(array->n * sizeof *set->mutations);
186 set->n_mutations = 0;
187 for (i = 0; i < array->n; i++) {
188 struct ovsdb_error *error;
189 error = ovsdb_mutation_from_json(ts, array->elems[i], symtab,
190 &set->mutations[i]);
191 if (error) {
192 ovsdb_mutation_set_destroy(set);
193 set->mutations = NULL;
194 set->n_mutations = 0;
195 return error;
196 }
197 set->n_mutations++;
198 }
199
200 return NULL;
201}
202
203static struct json *
204ovsdb_mutation_to_json(const struct ovsdb_mutation *m)
205{
206 return json_array_create_3(
207 json_string_create(m->column->name),
208 json_string_create(ovsdb_mutator_to_string(m->mutator)),
209 ovsdb_datum_to_json(&m->arg, &m->type));
210}
211
212struct json *
213ovsdb_mutation_set_to_json(const struct ovsdb_mutation_set *set)
214{
215 struct json **mutations;
216 size_t i;
217
218 mutations = xmalloc(set->n_mutations * sizeof *mutations);
219 for (i = 0; i < set->n_mutations; i++) {
220 mutations[i] = ovsdb_mutation_to_json(&set->mutations[i]);
221 }
222 return json_array_create(mutations, set->n_mutations);
223}
224
225void
226ovsdb_mutation_set_destroy(struct ovsdb_mutation_set *set)
227{
228 size_t i;
229
230 for (i = 0; i < set->n_mutations; i++) {
231 ovsdb_mutation_free(&set->mutations[i]);
232 }
233 free(set->mutations);
234}
bd76d25d
BP
235\f
236enum ovsdb_mutation_scalar_error {
237 ME_OK,
238 ME_DOM,
239 ME_RANGE
240};
241
242struct ovsdb_scalar_mutation {
243 int (*mutate_integer)(int64_t *x, int64_t y);
244 int (*mutate_real)(double *x, double y);
245 enum ovsdb_mutator mutator;
246};
247
248static const struct ovsdb_scalar_mutation add_mutation;
249static const struct ovsdb_scalar_mutation sub_mutation;
250static const struct ovsdb_scalar_mutation mul_mutation;
251static const struct ovsdb_scalar_mutation div_mutation;
252static const struct ovsdb_scalar_mutation mod_mutation;
253
254static struct ovsdb_error *
255ovsdb_mutation_scalar_error(enum ovsdb_mutation_scalar_error error,
256 enum ovsdb_mutator mutator)
257{
258 switch (error) {
259 case ME_OK:
260 return OVSDB_BUG("unexpected success");
261
262 case ME_DOM:
263 return ovsdb_error("domain error", "Division by zero.");
264
265 case ME_RANGE:
266 return ovsdb_error("range error",
267 "Result of \"%s\" operation is out of range.",
268 ovsdb_mutator_to_string(mutator));
269
270 default:
271 return OVSDB_BUG("unexpected error");
272 }
273}
274
275static int
276check_real_range(double x)
277{
278 return x >= -DBL_MAX && x <= DBL_MAX ? 0 : ME_RANGE;
279}
280
281static struct ovsdb_error *
282mutate_scalar(const struct ovsdb_type *dst_type, struct ovsdb_datum *dst,
283 const union ovsdb_atom *arg,
284 const struct ovsdb_scalar_mutation *mutation)
285{
286 const struct ovsdb_base_type *base = &dst_type->key;
287 struct ovsdb_error *error;
288 unsigned int i;
289
290 if (base->type == OVSDB_TYPE_INTEGER) {
291 int64_t y = arg->integer;
292 for (i = 0; i < dst->n; i++) {
293 enum ovsdb_mutation_scalar_error me;
294
295 me = (mutation->mutate_integer)(&dst->keys[i].integer, y);
296 if (me != ME_OK) {
297 return ovsdb_mutation_scalar_error(me, mutation->mutator);
298 }
299 }
300 } else if (base->type == OVSDB_TYPE_REAL) {
301 double y = arg->real;
302 for (i = 0; i < dst->n; i++) {
303 double *x = &dst->keys[i].real;
304 enum ovsdb_mutation_scalar_error me;
305
306 me = (mutation->mutate_real)(x, y);
307 if (me == ME_OK) {
308 me = check_real_range(*x);
309 }
310 if (me != ME_OK) {
311 return ovsdb_mutation_scalar_error(me, mutation->mutator);
312 }
313 }
314 } else {
428b2edd 315 OVS_NOT_REACHED();
bd76d25d
BP
316 }
317
318 for (i = 0; i < dst->n; i++) {
319 error = ovsdb_atom_check_constraints(&dst->keys[i], base);
320 if (error) {
321 return error;
322 }
323 }
324
bfc96d9b 325 error = ovsdb_datum_sort(dst, dst_type->key.type);
bd76d25d
BP
326 if (error) {
327 ovsdb_error_destroy(error);
328 return ovsdb_error("constraint violation",
329 "Result of \"%s\" operation contains duplicates.",
330 ovsdb_mutator_to_string(mutation->mutator));
331 }
332 return NULL;
333}
334
335static struct ovsdb_error *
336ovsdb_mutation_check_count(struct ovsdb_datum *dst,
337 const struct ovsdb_type *dst_type)
338{
339 if (!ovsdb_datum_conforms_to_type(dst, dst_type)) {
340 char *s = ovsdb_type_to_english(dst_type);
341 struct ovsdb_error *e = ovsdb_error(
b20ae4b3 342 "constraint violation",
bd76d25d
BP
343 "Attempted to store %u elements in %s.", dst->n, s);
344 free(s);
345 return e;
346 }
347 return NULL;
348}
349
350struct ovsdb_error *
351ovsdb_mutation_set_execute(struct ovsdb_row *row,
352 const struct ovsdb_mutation_set *set)
353{
354 size_t i;
355
356 for (i = 0; i < set->n_mutations; i++) {
357 const struct ovsdb_mutation *m = &set->mutations[i];
358 struct ovsdb_datum *dst = &row->fields[m->column->index];
359 const struct ovsdb_type *dst_type = &m->column->type;
360 const struct ovsdb_datum *arg = &set->mutations[i].arg;
361 const struct ovsdb_type *arg_type = &m->type;
362 struct ovsdb_error *error;
363
364 switch (m->mutator) {
365 case OVSDB_M_ADD:
366 error = mutate_scalar(dst_type, dst, &arg->keys[0], &add_mutation);
367 break;
368
369 case OVSDB_M_SUB:
370 error = mutate_scalar(dst_type, dst, &arg->keys[0], &sub_mutation);
371 break;
372
373 case OVSDB_M_MUL:
374 error = mutate_scalar(dst_type, dst, &arg->keys[0], &mul_mutation);
375 break;
376
377 case OVSDB_M_DIV:
378 error = mutate_scalar(dst_type, dst, &arg->keys[0], &div_mutation);
379 break;
380
381 case OVSDB_M_MOD:
382 error = mutate_scalar(dst_type, dst, &arg->keys[0], &mod_mutation);
383 break;
e9f8f936 384
bd76d25d
BP
385 case OVSDB_M_INSERT:
386 ovsdb_datum_union(dst, arg, dst_type, false);
387 error = ovsdb_mutation_check_count(dst, dst_type);
388 break;
389
390 case OVSDB_M_DELETE:
391 ovsdb_datum_subtract(dst, dst_type, arg, arg_type);
392 error = ovsdb_mutation_check_count(dst, dst_type);
393 break;
8b71367c
BP
394
395 default:
428b2edd 396 OVS_NOT_REACHED();
bd76d25d
BP
397 }
398 if (error) {
399 return error;
400 }
401 }
402
403 return NULL;
404}
405\f
e9f8f936
BP
406static int
407add_int(int64_t *x, int64_t y)
408{
409 /* Check for overflow. See _Hacker's Delight_ pp. 27. */
410 int64_t z = ~(*x ^ y) & INT64_MIN;
411 if ((~(*x ^ y) & ~(((*x ^ z) + y) ^ y)) >> 63) {
412 return ME_RANGE;
413 } else {
414 *x += y;
415 return 0;
416 }
417}
418
419static int
420sub_int(int64_t *x, int64_t y)
421{
422 /* Check for overflow. See _Hacker's Delight_ pp. 27. */
423 int64_t z = (*x ^ y) & INT64_MIN;
424 if (((*x ^ y) & (((*x ^ z) - y) ^ y)) >> 63) {
425 return ME_RANGE;
426 } else {
427 *x -= y;
428 return 0;
429 }
430}
431
432static int
433mul_int(int64_t *x, int64_t y)
434{
435 /* Check for overflow. See _Hacker's Delight_ pp. 30. */
436 if (*x > 0
437 ? (y > 0
438 ? *x >= INT64_MAX / y
439 : y < INT64_MIN / *x)
440 : (y > 0
441 ? *x < INT64_MIN / y
442 : *x != 0 && y < INT64_MAX / y)) {
443 return ME_RANGE;
444 } else {
445 *x *= y;
446 return 0;
447 }
448}
449
450static int
451check_int_div(int64_t x, int64_t y)
452{
453 /* Check for overflow. See _Hacker's Delight_ pp. 32. */
454 if (!y) {
455 return ME_DOM;
456 } else if (x == INT64_MIN && y == -1) {
457 return ME_RANGE;
458 } else {
459 return 0;
460 }
461}
462
463static int
464div_int(int64_t *x, int64_t y)
465{
466 int error = check_int_div(*x, y);
467 if (!error) {
468 *x /= y;
469 }
470 return error;
471}
472
473static int
474mod_int(int64_t *x, int64_t y)
475{
476 int error = check_int_div(*x, y);
477 if (!error) {
478 *x %= y;
479 }
480 return error;
481}
482
e9f8f936
BP
483static int
484add_double(double *x, double y)
485{
486 *x += y;
487 return 0;
488}
489
490static int
491sub_double(double *x, double y)
492{
493 *x -= y;
494 return 0;
495}
496
497static int
498mul_double(double *x, double y)
499{
500 *x *= y;
501 return 0;
502}
503
504static int
505div_double(double *x, double y)
506{
507 if (y == 0) {
508 return ME_DOM;
509 } else {
510 *x /= y;
511 return 0;
512 }
513}
514
bd76d25d
BP
515static const struct ovsdb_scalar_mutation add_mutation = {
516 add_int, add_double, OVSDB_M_ADD
517};
e9f8f936 518
bd76d25d
BP
519static const struct ovsdb_scalar_mutation sub_mutation = {
520 sub_int, sub_double, OVSDB_M_SUB
521};
e9f8f936 522
bd76d25d
BP
523static const struct ovsdb_scalar_mutation mul_mutation = {
524 mul_int, mul_double, OVSDB_M_MUL
525};
e9f8f936 526
bd76d25d
BP
527static const struct ovsdb_scalar_mutation div_mutation = {
528 div_int, div_double, OVSDB_M_DIV
529};
e9f8f936 530
bd76d25d
BP
531static const struct ovsdb_scalar_mutation mod_mutation = {
532 mod_int, NULL, OVSDB_M_MOD
533};