Branch data Line data Source code
1 : : /* Copyright (c) 2009, 2010, 2011, 2012, 2013 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 <limits.h>
19 : :
20 : : #include "column.h"
21 : : #include "condition.h"
22 : : #include "file.h"
23 : : #include "openvswitch/json.h"
24 : : #include "mutation.h"
25 : : #include "ovsdb-data.h"
26 : : #include "ovsdb-error.h"
27 : : #include "ovsdb-parser.h"
28 : : #include "ovsdb.h"
29 : : #include "query.h"
30 : : #include "row.h"
31 : : #include "server.h"
32 : : #include "table.h"
33 : : #include "timeval.h"
34 : : #include "transaction.h"
35 : :
36 : : struct ovsdb_execution {
37 : : struct ovsdb *db;
38 : : const struct ovsdb_session *session;
39 : : struct ovsdb_txn *txn;
40 : : struct ovsdb_symbol_table *symtab;
41 : : bool durable;
42 : :
43 : : /* Triggers. */
44 : : long long int elapsed_msec;
45 : : long long int timeout_msec;
46 : : };
47 : :
48 : : typedef struct ovsdb_error *ovsdb_operation_executor(struct ovsdb_execution *,
49 : : struct ovsdb_parser *,
50 : : struct json *result);
51 : :
52 : : static ovsdb_operation_executor ovsdb_execute_insert;
53 : : static ovsdb_operation_executor ovsdb_execute_select;
54 : : static ovsdb_operation_executor ovsdb_execute_update;
55 : : static ovsdb_operation_executor ovsdb_execute_mutate;
56 : : static ovsdb_operation_executor ovsdb_execute_delete;
57 : : static ovsdb_operation_executor ovsdb_execute_wait;
58 : : static ovsdb_operation_executor ovsdb_execute_commit;
59 : : static ovsdb_operation_executor ovsdb_execute_abort;
60 : : static ovsdb_operation_executor ovsdb_execute_comment;
61 : : static ovsdb_operation_executor ovsdb_execute_assert;
62 : :
63 : : static ovsdb_operation_executor *
64 : 78092 : lookup_executor(const char *name, bool *read_only)
65 : : {
66 : : struct ovsdb_operation {
67 : : const char *name;
68 : : bool read_only;
69 : : ovsdb_operation_executor *executor;
70 : : };
71 : :
72 : : static const struct ovsdb_operation operations[] = {
73 : : { "insert", false, ovsdb_execute_insert },
74 : : { "select", true, ovsdb_execute_select },
75 : : { "update", false, ovsdb_execute_update },
76 : : { "mutate", false, ovsdb_execute_mutate },
77 : : { "delete", false, ovsdb_execute_delete },
78 : : { "wait", true, ovsdb_execute_wait },
79 : : { "commit", false, ovsdb_execute_commit },
80 : : { "abort", true, ovsdb_execute_abort },
81 : : { "comment", true, ovsdb_execute_comment },
82 : : { "assert", true, ovsdb_execute_assert },
83 : : };
84 : :
85 : : size_t i;
86 : :
87 [ + - ]: 345891 : for (i = 0; i < ARRAY_SIZE(operations); i++) {
88 : 345891 : const struct ovsdb_operation *c = &operations[i];
89 [ + + ]: 345891 : if (!strcmp(c->name, name)) {
90 : 78092 : *read_only = c->read_only;
91 : 78092 : return c->executor;
92 : : }
93 : : }
94 : 0 : return NULL;
95 : : }
96 : :
97 : : struct json *
98 : 12583 : ovsdb_execute(struct ovsdb *db, const struct ovsdb_session *session,
99 : : const struct json *params, bool read_only,
100 : : long long int elapsed_msec, long long int *timeout_msec)
101 : : {
102 : : struct ovsdb_execution x;
103 : : struct ovsdb_error *error;
104 : : struct json *results;
105 : : size_t n_operations;
106 : : size_t i;
107 : :
108 [ + - ]: 12583 : if (params->type != JSON_ARRAY
109 [ + - ]: 12583 : || !params->u.array.n
110 [ + - ]: 12583 : || params->u.array.elems[0]->type != JSON_STRING
111 [ - + ]: 12583 : || strcmp(params->u.array.elems[0]->u.string, db->schema->name)) {
112 [ # # ]: 0 : if (params->type != JSON_ARRAY) {
113 : 0 : error = ovsdb_syntax_error(params, NULL, "array expected");
114 : : } else {
115 : 0 : error = ovsdb_syntax_error(params, NULL, "database name expected "
116 : : "as first parameter");
117 : : }
118 : :
119 : 0 : results = ovsdb_error_to_json(error);
120 : 0 : ovsdb_error_destroy(error);
121 : 0 : return results;
122 : : }
123 : :
124 : 12583 : x.db = db;
125 : 12583 : x.session = session;
126 : 12583 : x.txn = ovsdb_txn_create(db);
127 : 12583 : x.symtab = ovsdb_symbol_table_create();
128 : 12583 : x.durable = false;
129 : 12583 : x.elapsed_msec = elapsed_msec;
130 : 12583 : x.timeout_msec = LLONG_MAX;
131 : 12583 : results = NULL;
132 : :
133 : 12583 : results = json_array_create_empty();
134 : 12583 : n_operations = params->u.array.n - 1;
135 : 12583 : error = NULL;
136 [ + + ]: 90577 : for (i = 1; i <= n_operations; i++) {
137 : 78092 : struct json *operation = params->u.array.elems[i];
138 : : struct ovsdb_error *parse_error;
139 : : struct ovsdb_parser parser;
140 : : struct json *result;
141 : : const struct json *op;
142 : 78092 : const char *op_name = NULL;
143 : 78092 : bool ro = false;
144 : :
145 : : /* Parse and execute operation. */
146 : 78092 : ovsdb_parser_init(&parser, operation,
147 : : "ovsdb operation %"PRIuSIZE" of %"PRIuSIZE, i,
148 : : n_operations);
149 : 78092 : op = ovsdb_parser_member(&parser, "op", OP_ID);
150 : 78092 : result = json_object_create();
151 [ + - ]: 78092 : if (op) {
152 : 78092 : op_name = json_string(op);
153 : 78092 : ovsdb_operation_executor *executor = lookup_executor(op_name, &ro);
154 [ + - ]: 78092 : if (executor) {
155 : 78092 : error = executor(&x, &parser, result);
156 : : } else {
157 : 78092 : ovsdb_parser_raise_error(&parser, "No operation \"%s\"",
158 : : op_name);
159 : : }
160 : : } else {
161 [ # # ]: 0 : ovs_assert(ovsdb_parser_has_error(&parser));
162 : : }
163 : :
164 : : /* A parse error overrides any other error.
165 : : * An error overrides any other result. */
166 : 78092 : parse_error = ovsdb_parser_finish(&parser);
167 [ + + ]: 78092 : if (parse_error) {
168 : 1 : ovsdb_error_destroy(error);
169 : 1 : error = parse_error;
170 : : }
171 : : /* Create read-only violation error if there is one. */
172 [ + + ][ + + ]: 78092 : if (!error && read_only && !ro) {
[ + + ]
173 : 2 : error = ovsdb_error("not allowed",
174 : : "%s operation not allowed when "
175 : : "database server is in read only mode",
176 : : op_name);
177 : : }
178 [ + + ]: 78092 : if (error) {
179 : 98 : json_destroy(result);
180 : 98 : result = ovsdb_error_to_json(error);
181 : : }
182 [ + + ][ + + ]: 78092 : if (error && !strcmp(ovsdb_error_get_tag(error), "not supported")
183 [ + - ]: 6 : && timeout_msec) {
184 : 6 : ovsdb_txn_abort(x.txn);
185 : 6 : *timeout_msec = x.timeout_msec;
186 : :
187 : 6 : json_destroy(result);
188 : 6 : json_destroy(results);
189 : 6 : results = NULL;
190 : 6 : goto exit;
191 : : }
192 : :
193 : : /* Add result to array. */
194 : 78086 : json_array_add(results, result);
195 [ + + ]: 78086 : if (error) {
196 : 92 : break;
197 : : }
198 : : }
199 : :
200 [ + + ]: 12577 : if (!error) {
201 : 12485 : error = ovsdb_txn_commit(x.txn, x.durable);
202 [ + + ]: 12485 : if (error) {
203 : 12485 : json_array_add(results, ovsdb_error_to_json(error));
204 : : }
205 : : } else {
206 : 92 : ovsdb_txn_abort(x.txn);
207 : : }
208 : :
209 [ + + ]: 12586 : while (json_array(results)->n < n_operations) {
210 : 9 : json_array_add(results, json_null_create());
211 : : }
212 : :
213 : : exit:
214 : 12583 : ovsdb_error_destroy(error);
215 : 12583 : ovsdb_symbol_table_destroy(x.symtab);
216 : :
217 : 12583 : return results;
218 : : }
219 : :
220 : : static struct ovsdb_error *
221 : 14 : ovsdb_execute_commit(struct ovsdb_execution *x, struct ovsdb_parser *parser,
222 : : struct json *result OVS_UNUSED)
223 : : {
224 : : const struct json *durable;
225 : :
226 : 14 : durable = ovsdb_parser_member(parser, "durable", OP_BOOLEAN);
227 [ + - ][ + + ]: 14 : if (durable && json_boolean(durable)) {
228 : 7 : x->durable = true;
229 : : }
230 : 14 : return NULL;
231 : : }
232 : :
233 : : static struct ovsdb_error *
234 : 0 : ovsdb_execute_abort(struct ovsdb_execution *x OVS_UNUSED,
235 : : struct ovsdb_parser *parser OVS_UNUSED,
236 : : struct json *result OVS_UNUSED)
237 : : {
238 : 0 : return ovsdb_error("aborted", "aborted by request");
239 : : }
240 : :
241 : : static struct ovsdb_table *
242 : 68451 : parse_table(struct ovsdb_execution *x,
243 : : struct ovsdb_parser *parser, const char *member)
244 : : {
245 : : struct ovsdb_table *table;
246 : : const char *table_name;
247 : : const struct json *json;
248 : :
249 : 68451 : json = ovsdb_parser_member(parser, member, OP_ID);
250 [ - + ]: 68451 : if (!json) {
251 : 0 : return NULL;
252 : : }
253 : 68451 : table_name = json_string(json);
254 : :
255 : 68451 : table = shash_find_data(&x->db->tables, table_name);
256 [ - + ]: 68451 : if (!table) {
257 : 0 : ovsdb_parser_raise_error(parser, "No table named %s.", table_name);
258 : : }
259 : 68451 : return table;
260 : : }
261 : :
262 : : static OVS_WARN_UNUSED_RESULT struct ovsdb_error *
263 : 35784 : parse_row(const struct json *json, const struct ovsdb_table *table,
264 : : struct ovsdb_symbol_table *symtab,
265 : : struct ovsdb_row **rowp, struct ovsdb_column_set *columns)
266 : : {
267 : : struct ovsdb_error *error;
268 : : struct ovsdb_row *row;
269 : :
270 : 35784 : *rowp = NULL;
271 : :
272 [ - + ]: 35784 : if (!table) {
273 : 0 : return OVSDB_BUG("null table");
274 : : }
275 [ - + ]: 35784 : if (!json) {
276 : 0 : return OVSDB_BUG("null row");
277 : : }
278 : :
279 : 35784 : row = ovsdb_row_create(table);
280 : 35784 : error = ovsdb_row_from_json(row, json, symtab, columns);
281 [ + + ]: 35784 : if (error) {
282 : 15 : ovsdb_row_destroy(row);
283 : 15 : return error;
284 : : } else {
285 : 35769 : *rowp = row;
286 : 35769 : return NULL;
287 : : }
288 : : }
289 : :
290 : : static struct ovsdb_error *
291 : 17228 : ovsdb_execute_insert(struct ovsdb_execution *x, struct ovsdb_parser *parser,
292 : : struct json *result)
293 : : {
294 : : struct ovsdb_table *table;
295 : 17228 : struct ovsdb_row *row = NULL;
296 : : const struct json *uuid_name, *row_json;
297 : : struct ovsdb_error *error;
298 : : struct uuid row_uuid;
299 : :
300 : 17228 : table = parse_table(x, parser, "table");
301 : 17228 : uuid_name = ovsdb_parser_member(parser, "uuid-name", OP_ID | OP_OPTIONAL);
302 : 17228 : row_json = ovsdb_parser_member(parser, "row", OP_OBJECT);
303 : 17228 : error = ovsdb_parser_get_error(parser);
304 [ + + ]: 17228 : if (error) {
305 : 1 : return error;
306 : : }
307 : :
308 [ + + ]: 17227 : if (uuid_name) {
309 : : struct ovsdb_symbol *symbol;
310 : :
311 : 16528 : symbol = ovsdb_symbol_table_insert(x->symtab, json_string(uuid_name));
312 [ + + ]: 16528 : if (symbol->created) {
313 : 1 : return ovsdb_syntax_error(uuid_name, "duplicate uuid-name",
314 : : "This \"uuid-name\" appeared on an "
315 : : "earlier \"insert\" operation.");
316 : : }
317 : 16527 : row_uuid = symbol->uuid;
318 : 16527 : symbol->created = true;
319 : : } else {
320 : 699 : uuid_generate(&row_uuid);
321 : : }
322 : :
323 [ + - ]: 17226 : if (!error) {
324 : 17226 : error = parse_row(row_json, table, x->symtab, &row, NULL);
325 : : }
326 [ + + ]: 17226 : if (!error) {
327 : : /* Check constraints for columns not included in "row", in case the
328 : : * default values do not satisfy the constraints. We could check only
329 : : * the columns that have their default values by supplying an
330 : : * ovsdb_column_set to parse_row() above, but I suspect that this is
331 : : * cheaper. */
332 : : const struct shash_node *node;
333 : :
334 [ + + ][ - + ]: 333878 : SHASH_FOR_EACH (node, &table->schema->columns) {
335 : 316667 : const struct ovsdb_column *column = node->data;
336 : 316667 : const struct ovsdb_datum *datum = &row->fields[column->index];
337 : :
338 : : /* If there are 0 keys or pairs, there's nothing to check.
339 : : * If there is 1, it might be a default value.
340 : : * If there are more, it can't be a default value, so the value has
341 : : * already been checked. */
342 [ + + ]: 316667 : if (datum->n == 1) {
343 : 123717 : error = ovsdb_datum_check_constraints(datum, &column->type);
344 [ + + ]: 123717 : if (error) {
345 : 7 : ovsdb_row_destroy(row);
346 : 7 : break;
347 : : }
348 : : }
349 : : }
350 : : }
351 [ + + ]: 17226 : if (!error) {
352 : 17211 : *ovsdb_row_get_uuid_rw(row) = row_uuid;
353 : 17211 : ovsdb_txn_row_insert(x->txn, row);
354 : 17211 : json_object_put(result, "uuid",
355 : 17211 : ovsdb_datum_to_json(&row->fields[OVSDB_COL_UUID],
356 : : &ovsdb_type_uuid));
357 : : }
358 : 17228 : return error;
359 : : }
360 : :
361 : : static struct ovsdb_error *
362 : 2487 : ovsdb_execute_select(struct ovsdb_execution *x, struct ovsdb_parser *parser,
363 : : struct json *result)
364 : : {
365 : : struct ovsdb_table *table;
366 : : const struct json *where, *columns_json, *sort_json;
367 : 2487 : struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
368 : 2487 : struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
369 : 2487 : struct ovsdb_column_set sort = OVSDB_COLUMN_SET_INITIALIZER;
370 : : struct ovsdb_error *error;
371 : :
372 : 2487 : table = parse_table(x, parser, "table");
373 : 2487 : where = ovsdb_parser_member(parser, "where", OP_ARRAY);
374 : 2487 : columns_json = ovsdb_parser_member(parser, "columns",
375 : : OP_ARRAY | OP_OPTIONAL);
376 : 2487 : sort_json = ovsdb_parser_member(parser, "sort", OP_ARRAY | OP_OPTIONAL);
377 : :
378 : 2487 : error = ovsdb_parser_get_error(parser);
379 [ + - ]: 2487 : if (!error) {
380 : 2487 : error = ovsdb_condition_from_json(table->schema, where, x->symtab,
381 : : &condition);
382 : : }
383 [ + - ]: 2487 : if (!error) {
384 : 2487 : error = ovsdb_column_set_from_json(columns_json, table->schema,
385 : : &columns);
386 : : }
387 [ + - ]: 2487 : if (!error) {
388 : 2487 : error = ovsdb_column_set_from_json(sort_json, table->schema, &sort);
389 : : }
390 [ + - ]: 2487 : if (!error) {
391 : 2487 : struct ovsdb_row_set rows = OVSDB_ROW_SET_INITIALIZER;
392 : :
393 : 2487 : ovsdb_query_distinct(table, &condition, &columns, &rows);
394 : 2487 : ovsdb_row_set_sort(&rows, &sort);
395 : 2487 : json_object_put(result, "rows",
396 : : ovsdb_row_set_to_json(&rows, &columns));
397 : :
398 : 2487 : ovsdb_row_set_destroy(&rows);
399 : : }
400 : :
401 : 2487 : ovsdb_column_set_destroy(&columns);
402 : 2487 : ovsdb_column_set_destroy(&sort);
403 : 2487 : ovsdb_condition_destroy(&condition);
404 : :
405 : 2487 : return error;
406 : : }
407 : :
408 : : struct update_row_cbdata {
409 : : size_t n_matches;
410 : : struct ovsdb_txn *txn;
411 : : const struct ovsdb_row *row;
412 : : const struct ovsdb_column_set *columns;
413 : : };
414 : :
415 : : static bool
416 : 18636 : update_row_cb(const struct ovsdb_row *row, void *ur_)
417 : : {
418 : 18636 : struct update_row_cbdata *ur = ur_;
419 : :
420 : 18636 : ur->n_matches++;
421 [ + + ]: 18636 : if (!ovsdb_row_equal_columns(row, ur->row, ur->columns)) {
422 : 16240 : ovsdb_row_update_columns(ovsdb_txn_row_modify(ur->txn, row),
423 : : ur->row, ur->columns);
424 : : }
425 : :
426 : 18636 : return true;
427 : : }
428 : :
429 : : static struct ovsdb_error *
430 : 18558 : ovsdb_execute_update(struct ovsdb_execution *x, struct ovsdb_parser *parser,
431 : : struct json *result)
432 : : {
433 : : struct ovsdb_table *table;
434 : : const struct json *where, *row_json;
435 : 18558 : struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
436 : 18558 : struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
437 : 18558 : struct ovsdb_row *row = NULL;
438 : : struct update_row_cbdata ur;
439 : : struct ovsdb_error *error;
440 : :
441 : 18558 : table = parse_table(x, parser, "table");
442 : 18558 : where = ovsdb_parser_member(parser, "where", OP_ARRAY);
443 : 18558 : row_json = ovsdb_parser_member(parser, "row", OP_OBJECT);
444 : 18558 : error = ovsdb_parser_get_error(parser);
445 [ + - ]: 18558 : if (!error) {
446 : 18558 : error = parse_row(row_json, table, x->symtab, &row, &columns);
447 : : }
448 [ + + ]: 18558 : if (!error) {
449 : : size_t i;
450 : :
451 [ + + ]: 69467 : for (i = 0; i < columns.n_columns; i++) {
452 : 50930 : const struct ovsdb_column *column = columns.columns[i];
453 : :
454 [ + + ]: 50930 : if (!column->mutable) {
455 : 14 : error = ovsdb_syntax_error(parser->json,
456 : : "constraint violation",
457 : : "Cannot update immutable column %s "
458 : : "in table %s.",
459 : 14 : column->name, table->schema->name);
460 : 14 : break;
461 : : }
462 : : }
463 : : }
464 [ + + ]: 18558 : if (!error) {
465 : 18537 : error = ovsdb_condition_from_json(table->schema, where, x->symtab,
466 : : &condition);
467 : : }
468 [ + + ]: 18558 : if (!error) {
469 : 18537 : ur.n_matches = 0;
470 : 18537 : ur.txn = x->txn;
471 : 18537 : ur.row = row;
472 : 18537 : ur.columns = &columns;
473 : 18537 : ovsdb_query(table, &condition, update_row_cb, &ur);
474 : 18537 : json_object_put(result, "count", json_integer_create(ur.n_matches));
475 : : }
476 : :
477 : 18558 : ovsdb_row_destroy(row);
478 : 18558 : ovsdb_column_set_destroy(&columns);
479 : 18558 : ovsdb_condition_destroy(&condition);
480 : :
481 : 18558 : return error;
482 : : }
483 : :
484 : : struct mutate_row_cbdata {
485 : : size_t n_matches;
486 : : struct ovsdb_txn *txn;
487 : : const struct ovsdb_mutation_set *mutations;
488 : : struct ovsdb_error **error;
489 : : };
490 : :
491 : : static bool
492 : 2226 : mutate_row_cb(const struct ovsdb_row *row, void *mr_)
493 : : {
494 : 2226 : struct mutate_row_cbdata *mr = mr_;
495 : :
496 : 2226 : mr->n_matches++;
497 : 2226 : *mr->error = ovsdb_mutation_set_execute(ovsdb_txn_row_modify(mr->txn, row),
498 : : mr->mutations);
499 : 2226 : return *mr->error == NULL;
500 : : }
501 : :
502 : : static struct ovsdb_error *
503 : 2233 : ovsdb_execute_mutate(struct ovsdb_execution *x, struct ovsdb_parser *parser,
504 : : struct json *result)
505 : : {
506 : : struct ovsdb_table *table;
507 : : const struct json *where;
508 : : const struct json *mutations_json;
509 : 2233 : struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
510 : 2233 : struct ovsdb_mutation_set mutations = OVSDB_MUTATION_SET_INITIALIZER;
511 : 2233 : struct ovsdb_row *row = NULL;
512 : : struct mutate_row_cbdata mr;
513 : : struct ovsdb_error *error;
514 : :
515 : 2233 : table = parse_table(x, parser, "table");
516 : 2233 : where = ovsdb_parser_member(parser, "where", OP_ARRAY);
517 : 2233 : mutations_json = ovsdb_parser_member(parser, "mutations", OP_ARRAY);
518 : 2233 : error = ovsdb_parser_get_error(parser);
519 [ + - ]: 2233 : if (!error) {
520 : 2233 : error = ovsdb_mutation_set_from_json(table->schema, mutations_json,
521 : : x->symtab, &mutations);
522 : : }
523 [ + + ]: 2233 : if (!error) {
524 : 2219 : error = ovsdb_condition_from_json(table->schema, where, x->symtab,
525 : : &condition);
526 : : }
527 [ + + ]: 2233 : if (!error) {
528 : 2219 : mr.n_matches = 0;
529 : 2219 : mr.txn = x->txn;
530 : 2219 : mr.mutations = &mutations;
531 : 2219 : mr.error = &error;
532 : 2219 : ovsdb_query(table, &condition, mutate_row_cb, &mr);
533 : 2219 : json_object_put(result, "count", json_integer_create(mr.n_matches));
534 : : }
535 : :
536 : 2233 : ovsdb_row_destroy(row);
537 : 2233 : ovsdb_mutation_set_destroy(&mutations);
538 : 2233 : ovsdb_condition_destroy(&condition);
539 : :
540 : 2233 : return error;
541 : : }
542 : :
543 : : struct delete_row_cbdata {
544 : : size_t n_matches;
545 : : const struct ovsdb_table *table;
546 : : struct ovsdb_txn *txn;
547 : : };
548 : :
549 : : static bool
550 : 862 : delete_row_cb(const struct ovsdb_row *row, void *dr_)
551 : : {
552 : 862 : struct delete_row_cbdata *dr = dr_;
553 : :
554 : 862 : dr->n_matches++;
555 : 862 : ovsdb_txn_row_delete(dr->txn, row);
556 : :
557 : 862 : return true;
558 : : }
559 : :
560 : : static struct ovsdb_error *
561 : 824 : ovsdb_execute_delete(struct ovsdb_execution *x, struct ovsdb_parser *parser,
562 : : struct json *result)
563 : : {
564 : : struct ovsdb_table *table;
565 : : const struct json *where;
566 : 824 : struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
567 : : struct ovsdb_error *error;
568 : :
569 : 824 : where = ovsdb_parser_member(parser, "where", OP_ARRAY);
570 : 824 : table = parse_table(x, parser, "table");
571 : 824 : error = ovsdb_parser_get_error(parser);
572 [ + - ]: 824 : if (!error) {
573 : 824 : error = ovsdb_condition_from_json(table->schema, where, x->symtab,
574 : : &condition);
575 : : }
576 [ + - ]: 824 : if (!error) {
577 : : struct delete_row_cbdata dr;
578 : :
579 : 824 : dr.n_matches = 0;
580 : 824 : dr.table = table;
581 : 824 : dr.txn = x->txn;
582 : 824 : ovsdb_query(table, &condition, delete_row_cb, &dr);
583 : :
584 : 824 : json_object_put(result, "count", json_integer_create(dr.n_matches));
585 : : }
586 : :
587 : 824 : ovsdb_condition_destroy(&condition);
588 : :
589 : 824 : return error;
590 : : }
591 : :
592 : : struct wait_auxdata {
593 : : struct ovsdb_row_hash *actual;
594 : : struct ovsdb_row_hash *expected;
595 : : bool *equal;
596 : : };
597 : :
598 : : static bool
599 : 27164 : ovsdb_execute_wait_query_cb(const struct ovsdb_row *row, void *aux_)
600 : : {
601 : 27164 : struct wait_auxdata *aux = aux_;
602 : :
603 [ + + ]: 27164 : if (ovsdb_row_hash_contains(aux->expected, row)) {
604 : 27139 : ovsdb_row_hash_insert(aux->actual, row);
605 : 27139 : return true;
606 : : } else {
607 : : /* The query row isn't in the expected result set, so the actual and
608 : : * expected results sets definitely differ and we can short-circuit the
609 : : * rest of the query. */
610 : 25 : *aux->equal = false;
611 : 25 : return false;
612 : : }
613 : : }
614 : :
615 : : static struct ovsdb_error *
616 : 27121 : ovsdb_execute_wait(struct ovsdb_execution *x, struct ovsdb_parser *parser,
617 : : struct json *result OVS_UNUSED)
618 : : {
619 : : struct ovsdb_table *table;
620 : : const struct json *timeout, *where, *columns_json, *until, *rows;
621 : 27121 : struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER(&condition);
622 : 27121 : struct ovsdb_column_set columns = OVSDB_COLUMN_SET_INITIALIZER;
623 : 27121 : struct ovsdb_row_hash expected = OVSDB_ROW_HASH_INITIALIZER(expected);
624 : 27121 : struct ovsdb_row_hash actual = OVSDB_ROW_HASH_INITIALIZER(actual);
625 : : struct ovsdb_error *error;
626 : : struct wait_auxdata aux;
627 : 27121 : long long int timeout_msec = 0;
628 : : size_t i;
629 : :
630 : 27121 : timeout = ovsdb_parser_member(parser, "timeout", OP_NUMBER | OP_OPTIONAL);
631 : 27121 : where = ovsdb_parser_member(parser, "where", OP_ARRAY);
632 : 27121 : columns_json = ovsdb_parser_member(parser, "columns",
633 : : OP_ARRAY | OP_OPTIONAL);
634 : 27121 : until = ovsdb_parser_member(parser, "until", OP_STRING);
635 : 27121 : rows = ovsdb_parser_member(parser, "rows", OP_ARRAY);
636 : 27121 : table = parse_table(x, parser, "table");
637 : 27121 : error = ovsdb_parser_get_error(parser);
638 [ + - ]: 27121 : if (!error) {
639 : 27121 : error = ovsdb_condition_from_json(table->schema, where, x->symtab,
640 : : &condition);
641 : : }
642 [ + - ]: 27121 : if (!error) {
643 : 27121 : error = ovsdb_column_set_from_json(columns_json, table->schema,
644 : : &columns);
645 : : }
646 [ + - ]: 27121 : if (!error) {
647 [ + - ]: 27121 : if (timeout) {
648 [ - + ]: 27121 : timeout_msec = MIN(LLONG_MAX, json_real(timeout));
649 [ - + ]: 27121 : if (timeout_msec < 0) {
650 : 0 : error = ovsdb_syntax_error(timeout, NULL,
651 : : "timeout must be nonnegative");
652 [ + + ]: 27121 : } else if (timeout_msec < x->timeout_msec) {
653 : 27121 : x->timeout_msec = timeout_msec;
654 : : }
655 : : } else {
656 : 0 : timeout_msec = LLONG_MAX;
657 : : }
658 : : }
659 [ + - ]: 27121 : if (!error) {
660 [ + + ]: 27121 : if (strcmp(json_string(until), "==")
661 [ - + ]: 21 : && strcmp(json_string(until), "!=")) {
662 : 0 : error = ovsdb_syntax_error(until, NULL,
663 : : "\"until\" must be \"==\" or \"!=\"");
664 : : }
665 : : }
666 [ + - ]: 27121 : if (!error) {
667 : : /* Parse "rows" into 'expected'. */
668 : 27121 : ovsdb_row_hash_init(&expected, &columns);
669 [ + + ]: 54301 : for (i = 0; i < rows->u.array.n; i++) {
670 : : struct ovsdb_row *row;
671 : :
672 : 27180 : row = ovsdb_row_create(table);
673 : 27180 : error = ovsdb_row_from_json(row, rows->u.array.elems[i], x->symtab,
674 : : NULL);
675 [ - + ]: 27180 : if (error) {
676 : 0 : ovsdb_row_destroy(row);
677 : 0 : break;
678 : : }
679 : :
680 [ - + ]: 27180 : if (!ovsdb_row_hash_insert(&expected, row)) {
681 : : /* XXX Perhaps we should abort with an error or log a
682 : : * warning. */
683 : 0 : ovsdb_row_destroy(row);
684 : : }
685 : : }
686 : : }
687 [ + - ]: 27121 : if (!error) {
688 : : /* Execute query. */
689 : 27121 : bool equal = true;
690 : 27121 : ovsdb_row_hash_init(&actual, &columns);
691 : 27121 : aux.actual = &actual;
692 : 27121 : aux.expected = &expected;
693 : 27121 : aux.equal = &equal;
694 : 27121 : ovsdb_query(table, &condition, ovsdb_execute_wait_query_cb, &aux);
695 [ + + ]: 27121 : if (equal) {
696 : : /* We know that every row in 'actual' is also in 'expected'. We
697 : : * also know that all of the rows in 'actual' are distinct and that
698 : : * all of the rows in 'expected' are distinct. Therefore, if
699 : : * 'actual' and 'expected' have the same number of rows, then they
700 : : * have the same content. */
701 : 27096 : size_t n_actual = ovsdb_row_hash_count(&actual);
702 : 27096 : size_t n_expected = ovsdb_row_hash_count(&expected);
703 : 27096 : equal = n_actual == n_expected;
704 : : }
705 [ + + ]: 27121 : if (!strcmp(json_string(until), "==") != equal) {
706 [ + - ][ + + ]: 37 : if (timeout && x->elapsed_msec >= timeout_msec) {
707 [ + + ]: 62 : if (x->elapsed_msec) {
708 : 1 : error = ovsdb_error("timed out",
709 : : "\"wait\" timed out after %lld ms",
710 : : x->elapsed_msec);
711 : : } else {
712 : 30 : error = ovsdb_error("timed out",
713 : : "\"where\" clause test failed");
714 : : }
715 : : } else {
716 : : /* ovsdb_execute() will change this, if triggers really are
717 : : * supported. */
718 : 27121 : error = ovsdb_error("not supported", "triggers not supported");
719 : : }
720 : : }
721 : : }
722 : :
723 : :
724 : 27121 : ovsdb_row_hash_destroy(&expected, true);
725 : 27121 : ovsdb_row_hash_destroy(&actual, false);
726 : 27121 : ovsdb_column_set_destroy(&columns);
727 : 27121 : ovsdb_condition_destroy(&condition);
728 : :
729 : 27121 : return error;
730 : : }
731 : :
732 : : static struct ovsdb_error *
733 : 4131 : ovsdb_execute_comment(struct ovsdb_execution *x, struct ovsdb_parser *parser,
734 : : struct json *result OVS_UNUSED)
735 : : {
736 : : const struct json *comment;
737 : :
738 : 4131 : comment = ovsdb_parser_member(parser, "comment", OP_STRING);
739 [ - + ]: 4131 : if (!comment) {
740 : 0 : return NULL;
741 : : }
742 : 4131 : ovsdb_txn_add_comment(x->txn, json_string(comment));
743 : :
744 : 4131 : return NULL;
745 : : }
746 : :
747 : : static struct ovsdb_error *
748 : 5496 : ovsdb_execute_assert(struct ovsdb_execution *x, struct ovsdb_parser *parser,
749 : : struct json *result OVS_UNUSED)
750 : : {
751 : : const struct json *lock_name;
752 : :
753 : 5496 : lock_name = ovsdb_parser_member(parser, "lock", OP_ID);
754 [ - + ]: 5496 : if (!lock_name) {
755 : 0 : return NULL;
756 : : }
757 : :
758 [ + - ]: 5496 : if (x->session) {
759 : : const struct ovsdb_lock_waiter *waiter;
760 : :
761 : 5496 : waiter = ovsdb_session_get_lock_waiter(x->session,
762 : : json_string(lock_name));
763 [ + - ][ + - ]: 5496 : if (waiter && ovsdb_lock_waiter_is_owner(waiter)) {
764 : 5496 : return NULL;
765 : : }
766 : : }
767 : :
768 : 0 : return ovsdb_error("not owner", "Asserted lock %s not held.",
769 : : json_string(lock_name));
770 : : }
|