]>
Commit | Line | Data |
---|---|---|
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 | 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 | OVSDB_MUTATORS; | |
42 | #undef OVSDB_MUTATOR | |
43 | ||
44 | return ovsdb_syntax_error(NULL, "unknown mutator", | |
45 | "No mutator named %s.", name); | |
46 | } | |
47 | ||
48 | const char * | |
49 | ovsdb_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 | ||
60 | static OVS_WARN_UNUSED_RESULT struct ovsdb_error * | |
61 | type_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 | ||
76 | static OVS_WARN_UNUSED_RESULT struct ovsdb_error * | |
77 | 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 | if (json->type != JSON_ARRAY | |
88 | || json->array.n != 3 | |
89 | || json->array.elems[0]->type != JSON_STRING | |
90 | || json->array.elems[1]->type != JSON_STRING) { | |
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 | } | |
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 | ||
108 | ovsdb_type_clone(&m->type, &m->column->type); | |
109 | ||
110 | mutator_name = json_string(array->elems[1]); | |
111 | error = ovsdb_mutator_from_string(mutator_name, &m->mutator); | |
112 | if (error) { | |
113 | goto exit; | |
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)) | |
124 | || (m->type.key.type != OVSDB_TYPE_INTEGER | |
125 | && m->type.key.type != OVSDB_TYPE_REAL) | |
126 | || (m->mutator == OVSDB_M_MOD | |
127 | && m->type.key.type == OVSDB_TYPE_REAL)) { | |
128 | return type_mismatch(m, json); | |
129 | } | |
130 | ovsdb_base_type_clear_constraints(&m->type.key); | |
131 | m->type.n_min = m->type.n_max = 1; | |
132 | error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2], | |
133 | symtab); | |
134 | break; | |
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); | |
150 | ovsdb_base_type_destroy(&m->type.value); | |
151 | m->type.value.enum_ = NULL; | |
152 | m->type.value.type = OVSDB_TYPE_VOID; | |
153 | error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2], | |
154 | symtab); | |
155 | } | |
156 | break; | |
157 | ||
158 | default: | |
159 | OVS_NOT_REACHED(); | |
160 | } | |
161 | ||
162 | exit: | |
163 | if (error) { | |
164 | ovsdb_type_destroy(&m->type); | |
165 | } | |
166 | return error; | |
167 | } | |
168 | ||
169 | static void | |
170 | ovsdb_mutation_free(struct ovsdb_mutation *m) | |
171 | { | |
172 | ovsdb_datum_destroy(&m->arg, &m->type); | |
173 | ovsdb_type_destroy(&m->type); | |
174 | } | |
175 | ||
176 | struct ovsdb_error * | |
177 | ovsdb_mutation_set_from_json(const struct ovsdb_table_schema *ts, | |
178 | const struct json *json, | |
179 | struct ovsdb_symbol_table *symtab, | |
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 | ||
203 | static struct json * | |
204 | ovsdb_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 | ||
212 | struct json * | |
213 | ovsdb_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 | ||
225 | void | |
226 | ovsdb_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 | } | |
235 | \f | |
236 | enum ovsdb_mutation_scalar_error { | |
237 | ME_OK, | |
238 | ME_DOM, | |
239 | ME_RANGE | |
240 | }; | |
241 | ||
242 | struct 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 | ||
248 | static const struct ovsdb_scalar_mutation add_mutation; | |
249 | static const struct ovsdb_scalar_mutation sub_mutation; | |
250 | static const struct ovsdb_scalar_mutation mul_mutation; | |
251 | static const struct ovsdb_scalar_mutation div_mutation; | |
252 | static const struct ovsdb_scalar_mutation mod_mutation; | |
253 | ||
254 | static struct ovsdb_error * | |
255 | ovsdb_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 | ||
275 | static int | |
276 | check_real_range(double x) | |
277 | { | |
278 | return x >= -DBL_MAX && x <= DBL_MAX ? 0 : ME_RANGE; | |
279 | } | |
280 | ||
281 | static struct ovsdb_error * | |
282 | mutate_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 { | |
315 | OVS_NOT_REACHED(); | |
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 | ||
325 | error = ovsdb_datum_sort(dst, dst_type->key.type); | |
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 | ||
335 | static struct ovsdb_error * | |
336 | ovsdb_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( | |
342 | "constraint violation", | |
343 | "Attempted to store %u elements in %s.", dst->n, s); | |
344 | free(s); | |
345 | return e; | |
346 | } | |
347 | return NULL; | |
348 | } | |
349 | ||
350 | struct ovsdb_error * | |
351 | ovsdb_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; | |
384 | ||
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; | |
394 | ||
395 | default: | |
396 | OVS_NOT_REACHED(); | |
397 | } | |
398 | if (error) { | |
399 | return error; | |
400 | } | |
401 | } | |
402 | ||
403 | return NULL; | |
404 | } | |
405 | \f | |
406 | static int | |
407 | add_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 | ||
419 | static int | |
420 | sub_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 | ||
432 | static int | |
433 | mul_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 | ||
450 | static int | |
451 | check_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 | ||
463 | static int | |
464 | div_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 | ||
473 | static int | |
474 | mod_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 | ||
483 | static int | |
484 | add_double(double *x, double y) | |
485 | { | |
486 | *x += y; | |
487 | return 0; | |
488 | } | |
489 | ||
490 | static int | |
491 | sub_double(double *x, double y) | |
492 | { | |
493 | *x -= y; | |
494 | return 0; | |
495 | } | |
496 | ||
497 | static int | |
498 | mul_double(double *x, double y) | |
499 | { | |
500 | *x *= y; | |
501 | return 0; | |
502 | } | |
503 | ||
504 | static int | |
505 | div_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 | ||
515 | static const struct ovsdb_scalar_mutation add_mutation = { | |
516 | add_int, add_double, OVSDB_M_ADD | |
517 | }; | |
518 | ||
519 | static const struct ovsdb_scalar_mutation sub_mutation = { | |
520 | sub_int, sub_double, OVSDB_M_SUB | |
521 | }; | |
522 | ||
523 | static const struct ovsdb_scalar_mutation mul_mutation = { | |
524 | mul_int, mul_double, OVSDB_M_MUL | |
525 | }; | |
526 | ||
527 | static const struct ovsdb_scalar_mutation div_mutation = { | |
528 | div_int, div_double, OVSDB_M_DIV | |
529 | }; | |
530 | ||
531 | static const struct ovsdb_scalar_mutation mod_mutation = { | |
532 | mod_int, NULL, OVSDB_M_MOD | |
533 | }; |