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