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