]> git.proxmox.com Git - mirror_ovs.git/blob - tests/test-ovsdb.c
ovn: specify addresses of type "router" lsps as "router"
[mirror_ovs.git] / tests / test-ovsdb.c
1 /*
2 * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2015, 2016, 2017 Nicira, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <config.h>
18
19 #include <assert.h>
20 #include <fcntl.h>
21 #include <getopt.h>
22 #include <inttypes.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include "byte-order.h"
27 #include "command-line.h"
28 #include "openvswitch/dynamic-string.h"
29 #include "openvswitch/json.h"
30 #include "jsonrpc.h"
31 #include "ovsdb-data.h"
32 #include "ovsdb-error.h"
33 #include "ovsdb-idl.h"
34 #include "ovsdb-types.h"
35 #include "ovsdb/column.h"
36 #include "ovsdb/condition.h"
37 #include "ovsdb/file.h"
38 #include "ovsdb/log.h"
39 #include "ovsdb/mutation.h"
40 #include "ovsdb/ovsdb.h"
41 #include "ovsdb/query.h"
42 #include "ovsdb/row.h"
43 #include "ovsdb/server.h"
44 #include "ovsdb/table.h"
45 #include "ovsdb/transaction.h"
46 #include "ovsdb/trigger.h"
47 #include "poll-loop.h"
48 #include "stream.h"
49 #include "svec.h"
50 #include "tests/idltest.h"
51 #include "timeval.h"
52 #include "util.h"
53 #include "openvswitch/vlog.h"
54
55 struct test_ovsdb_pvt_context {
56 bool track;
57 };
58
59 OVS_NO_RETURN static void usage(void);
60 static void parse_options(int argc, char *argv[],
61 struct test_ovsdb_pvt_context *pvt);
62 static struct ovs_cmdl_command *get_all_commands(void);
63
64 int
65 main(int argc, char *argv[])
66 {
67 struct test_ovsdb_pvt_context pvt = {.track = false};
68 struct ovs_cmdl_context ctx = { .argc = 0, .pvt = &pvt};
69 set_program_name(argv[0]);
70 parse_options(argc, argv, &pvt);
71 ctx.argc = argc - optind;
72 ctx.argv = argv + optind;
73 ovs_cmdl_run_command(&ctx, get_all_commands());
74 return 0;
75 }
76
77 static void
78 parse_options(int argc, char *argv[], struct test_ovsdb_pvt_context *pvt)
79 {
80 static const struct option long_options[] = {
81 {"timeout", required_argument, NULL, 't'},
82 {"verbose", optional_argument, NULL, 'v'},
83 {"change-track", optional_argument, NULL, 'c'},
84 {"help", no_argument, NULL, 'h'},
85 {NULL, 0, NULL, 0},
86 };
87 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
88
89 for (;;) {
90 unsigned long int timeout;
91 int c;
92
93 c = getopt_long(argc, argv, short_options, long_options, NULL);
94 if (c == -1) {
95 break;
96 }
97
98 switch (c) {
99 case 't':
100 timeout = strtoul(optarg, NULL, 10);
101 if (timeout <= 0) {
102 ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
103 optarg);
104 } else {
105 time_alarm(timeout);
106 }
107 break;
108
109 case 'h':
110 usage();
111
112 case 'v':
113 vlog_set_verbosity(optarg);
114 break;
115
116 case 'c':
117 pvt->track = true;
118 break;
119
120 case '?':
121 exit(EXIT_FAILURE);
122
123 default:
124 abort();
125 }
126 }
127 free(short_options);
128 }
129
130 static void
131 usage(void)
132 {
133 printf("%s: Open vSwitch database test utility\n"
134 "usage: %s [OPTIONS] COMMAND [ARG...]\n\n"
135 " log-io FILE FLAGS COMMAND...\n"
136 " open FILE with FLAGS, run COMMANDs\n"
137 " default-atoms\n"
138 " test ovsdb_atom_default()\n"
139 " default-data\n"
140 " test ovsdb_datum_default()\n"
141 " parse-atomic-type TYPE\n"
142 " parse TYPE as OVSDB atomic type, and re-serialize\n"
143 " parse-base-type TYPE\n"
144 " parse TYPE as OVSDB base type, and re-serialize\n"
145 " parse-type JSON\n"
146 " parse JSON as OVSDB type, and re-serialize\n"
147 " parse-atoms TYPE ATOM...\n"
148 " parse JSON ATOMs as atoms of TYPE, and re-serialize\n"
149 " parse-atom-strings TYPE ATOM...\n"
150 " parse string ATOMs as atoms of given TYPE, and re-serialize\n"
151 " sort-atoms TYPE ATOM...\n"
152 " print JSON ATOMs in sorted order\n"
153 " parse-data TYPE DATUM...\n"
154 " parse JSON DATUMs as data of given TYPE, and re-serialize\n"
155 " parse-data-strings TYPE DATUM...\n"
156 " parse string DATUMs as data of given TYPE, and re-serialize\n"
157 " parse-column NAME OBJECT\n"
158 " parse column NAME with info OBJECT, and re-serialize\n"
159 " parse-table NAME OBJECT [DEFAULT-IS-ROOT]\n"
160 " parse table NAME with info OBJECT\n"
161 " parse-row TABLE ROW..., and re-serialize\n"
162 " parse each ROW of defined TABLE\n"
163 " compare-row TABLE ROW...\n"
164 " mutually compare all of the ROWs, print those that are equal\n"
165 " parse-conditions TABLE CONDITION...\n"
166 " parse each CONDITION on TABLE, and re-serialize\n"
167 " evaluate-conditions TABLE [CONDITION,...] [ROW,...]\n"
168 " test CONDITIONS on TABLE against each ROW, print results\n"
169 " evaluate-conditions-any TABLE [CONDITION,...] [ROW,...]\n"
170 " test CONDITIONS to match any of the CONDITONS on TABLE\n"
171 " against each ROW, print results\n"
172 " compare-conditions TABLE [CONDITION,...]\n"
173 " mutually compare all of the CONDITION, print results for\n"
174 " each pair\n"
175 " parse-mutations TABLE MUTATION...\n"
176 " parse each MUTATION on TABLE, and re-serialize\n"
177 " execute-mutations TABLE [MUTATION,...] [ROW,...]\n"
178 " execute MUTATIONS on TABLE on each ROW, print results\n"
179 " query TABLE [ROW,...] [CONDITION,...]\n"
180 " add each ROW to TABLE, then query and print the rows that\n"
181 " satisfy each CONDITION.\n"
182 " query-distinct TABLE [ROW,...] [CONDITION,...] COLUMNS\n"
183 " add each ROW to TABLE, then query and print the rows that\n"
184 " satisfy each CONDITION and have distinct COLUMNS.\n"
185 " parse-schema JSON\n"
186 " parse JSON as an OVSDB schema, and re-serialize\n"
187 " transact COMMAND\n"
188 " execute each specified transactional COMMAND:\n"
189 " commit\n"
190 " abort\n"
191 " insert UUID I J\n"
192 " delete UUID\n"
193 " modify UUID I J\n"
194 " print\n"
195 " execute SCHEMA TRANSACTION...\n"
196 " executes each TRANSACTION on an initially empty database\n"
197 " the specified SCHEMA\n"
198 " execute-readonly SCHEMA TRANSACTION...\n"
199 " same as execute, except the TRANSACTION will be executed\n"
200 " against the database server that is in read only mode\n"
201 " trigger SCHEMA TRANSACTION...\n"
202 " executes each TRANSACTION on an initially empty database\n"
203 " the specified SCHEMA. A TRANSACTION of the form\n"
204 " [\"advance\", NUMBER] advances NUMBER milliseconds in\n"
205 " simulated time, for causing triggers to time out.\n"
206 " idl SERVER [TRANSACTION...]\n"
207 " connect to SERVER and dump the contents of the database\n"
208 " as seen initially by the IDL implementation and after\n"
209 " executing each TRANSACTION. (Each TRANSACTION must modify\n"
210 " the database or this command will hang.)\n"
211 " idl-partial-update-map-column SERVER \n"
212 " connect to SERVER and executes different operations to\n"
213 " test the capacity of updating elements inside a map column\n"
214 " displaying the table information after each operation.\n"
215 " idl-partial-update-set-column SERVER \n"
216 " connect to SERVER and executes different operations to\n"
217 " test the capacity of updating elements inside a set column\n"
218 " displaying the table information after each operation.\n",
219 program_name, program_name);
220 vlog_usage();
221 printf("\nOther options:\n"
222 " -t, --timeout=SECS give up after SECS seconds\n"
223 " -h, --help display this help message\n"
224 " -c, --change-track used with the 'idl' command to\n"
225 " enable tracking of IDL changes\n");
226 exit(EXIT_SUCCESS);
227 }
228 \f
229 /* Command helper functions. */
230
231 static struct json *
232 parse_json(const char *s)
233 {
234 struct json *json = json_from_string(s);
235 if (json->type == JSON_STRING) {
236 ovs_fatal(0, "\"%s\": %s", s, json->u.string);
237 }
238 return json;
239 }
240
241 static struct json *
242 unbox_json(struct json *json)
243 {
244 if (json->type == JSON_ARRAY && json->u.array.n == 1) {
245 struct json *inner = json->u.array.elems[0];
246 json->u.array.elems[0] = NULL;
247 json_destroy(json);
248 return inner;
249 } else {
250 return json;
251 }
252 }
253
254 static void
255 print_and_free_json(struct json *json)
256 {
257 char *string = json_to_string(json, JSSF_SORT);
258 json_destroy(json);
259 puts(string);
260 free(string);
261 }
262
263 static void
264 print_and_free_ovsdb_error(struct ovsdb_error *error)
265 {
266 char *string = ovsdb_error_to_string(error);
267 ovsdb_error_destroy(error);
268 puts(string);
269 free(string);
270 }
271
272 static void
273 check_ovsdb_error(struct ovsdb_error *error)
274 {
275 if (error) {
276 char *s = ovsdb_error_to_string(error);
277 ovsdb_error_destroy(error);
278 ovs_fatal(0, "%s", s);
279 }
280 }
281
282 static void
283 die_if_error(char *error)
284 {
285 if (error) {
286 ovs_fatal(0, "%s", error);
287 }
288 }
289 \f
290 /* Command implementations. */
291
292 static void
293 do_log_io(struct ovs_cmdl_context *ctx)
294 {
295 const char *name = ctx->argv[1];
296 char *mode_string = ctx->argv[2];
297
298 struct ovsdb_error *error;
299 enum ovsdb_log_open_mode mode;
300 struct ovsdb_log *log;
301 int i;
302
303 if (!strcmp(mode_string, "read-only")) {
304 mode = OVSDB_LOG_READ_ONLY;
305 } else if (!strcmp(mode_string, "read/write")) {
306 mode = OVSDB_LOG_READ_WRITE;
307 } else if (!strcmp(mode_string, "create")) {
308 mode = OVSDB_LOG_CREATE;
309 } else {
310 ovs_fatal(0, "unknown log-io open mode \"%s\"", mode_string);
311 }
312
313 check_ovsdb_error(ovsdb_log_open(name, mode, -1, &log));
314 printf("%s: open successful\n", name);
315
316 for (i = 3; i < ctx->argc; i++) {
317 const char *command = ctx->argv[i];
318 if (!strcmp(command, "read")) {
319 struct json *json;
320
321 error = ovsdb_log_read(log, &json);
322 if (!error) {
323 printf("%s: read: ", name);
324 if (json) {
325 print_and_free_json(json);
326 } else {
327 printf("end of log\n");
328 }
329 continue;
330 }
331 } else if (!strncmp(command, "write:", 6)) {
332 struct json *json = parse_json(command + 6);
333 error = ovsdb_log_write(log, json);
334 json_destroy(json);
335 } else if (!strcmp(command, "commit")) {
336 error = ovsdb_log_commit(log);
337 } else {
338 ovs_fatal(0, "unknown log-io command \"%s\"", command);
339 }
340 if (error) {
341 char *s = ovsdb_error_to_string(error);
342 printf("%s: %s failed: %s\n", name, command, s);
343 free(s);
344 ovsdb_error_destroy(error);
345 } else {
346 printf("%s: %s successful\n", name, command);
347 }
348 }
349
350 ovsdb_log_close(log);
351 }
352
353 static void
354 do_default_atoms(struct ovs_cmdl_context *ctx OVS_UNUSED)
355 {
356 int type;
357
358 for (type = 0; type < OVSDB_N_TYPES; type++) {
359 union ovsdb_atom atom;
360
361 if (type == OVSDB_TYPE_VOID) {
362 continue;
363 }
364
365 printf("%s: ", ovsdb_atomic_type_to_string(type));
366
367 ovsdb_atom_init_default(&atom, type);
368 if (!ovsdb_atom_equals(&atom, ovsdb_atom_default(type), type)) {
369 printf("wrong\n");
370 exit(1);
371 }
372 ovsdb_atom_destroy(&atom, type);
373
374 printf("OK\n");
375 }
376 }
377
378 static void
379 do_default_data(struct ovs_cmdl_context *ctx OVS_UNUSED)
380 {
381 unsigned int n_min;
382 int key, value;
383
384 for (n_min = 0; n_min <= 1; n_min++) {
385 for (key = 0; key < OVSDB_N_TYPES; key++) {
386 if (key == OVSDB_TYPE_VOID) {
387 continue;
388 }
389 for (value = 0; value < OVSDB_N_TYPES; value++) {
390 struct ovsdb_datum datum;
391 struct ovsdb_type type;
392
393 ovsdb_base_type_init(&type.key, key);
394 ovsdb_base_type_init(&type.value, value);
395 type.n_min = n_min;
396 type.n_max = 1;
397 assert(ovsdb_type_is_valid(&type));
398
399 printf("key %s, value %s, n_min %u: ",
400 ovsdb_atomic_type_to_string(key),
401 ovsdb_atomic_type_to_string(value), n_min);
402
403 ovsdb_datum_init_default(&datum, &type);
404 if (!ovsdb_datum_equals(&datum, ovsdb_datum_default(&type),
405 &type)) {
406 printf("wrong\n");
407 exit(1);
408 }
409 ovsdb_datum_destroy(&datum, &type);
410 ovsdb_type_destroy(&type);
411
412 printf("OK\n");
413 }
414 }
415 }
416 }
417
418 static void
419 do_diff_data(struct ovs_cmdl_context *ctx)
420 {
421 struct ovsdb_type type;
422 struct json *json;
423 struct ovsdb_datum new, old, diff, reincarnation;
424
425 json = unbox_json(parse_json(ctx->argv[1]));
426 check_ovsdb_error(ovsdb_type_from_json(&type, json));
427 json_destroy(json);
428
429 /* Arguments in pairs of 'old' and 'new'. */
430 for (int i = 2; i < ctx->argc - 1; i+=2) {
431 struct ovsdb_error *error;
432
433 json = unbox_json(parse_json(ctx->argv[i]));
434 check_ovsdb_error(ovsdb_datum_from_json(&old, &type, json, NULL));
435 json_destroy(json);
436
437 json = unbox_json(parse_json(ctx->argv[i+1]));
438 check_ovsdb_error(ovsdb_transient_datum_from_json(&new, &type, json));
439 json_destroy(json);
440
441 /* Generate the diff. */
442 ovsdb_datum_diff(&diff, &old, &new, &type);
443
444 /* Apply diff to 'old' to create'reincarnation'. */
445 error = ovsdb_datum_apply_diff(&reincarnation, &old, &diff, &type);
446 if (error) {
447 char *string = ovsdb_error_to_string(error);
448 ovsdb_error_destroy(error);
449 ovs_fatal(0, "%s", string);
450 }
451
452 /* Test to make sure 'new' equals 'reincarnation'. */
453 if (!ovsdb_datum_equals(&new, &reincarnation, &type)) {
454 ovs_fatal(0, "failed to apply diff");
455 }
456
457 /* Print diff */
458 json = ovsdb_datum_to_json(&diff, &type);
459 printf ("diff: ");
460 print_and_free_json(json);
461
462 /* Print reincarnation */
463 json = ovsdb_datum_to_json(&reincarnation, &type);
464 printf ("apply diff: ");
465 print_and_free_json(json);
466
467 ovsdb_datum_destroy(&new, &type);
468 ovsdb_datum_destroy(&old, &type);
469 ovsdb_datum_destroy(&diff, &type);
470 ovsdb_datum_destroy(&reincarnation, &type);
471
472 printf("OK\n");
473 }
474
475 ovsdb_type_destroy(&type);
476 }
477
478 static void
479 do_parse_atomic_type(struct ovs_cmdl_context *ctx)
480 {
481 enum ovsdb_atomic_type type;
482 struct json *json;
483
484 json = unbox_json(parse_json(ctx->argv[1]));
485 check_ovsdb_error(ovsdb_atomic_type_from_json(&type, json));
486 json_destroy(json);
487 print_and_free_json(ovsdb_atomic_type_to_json(type));
488 }
489
490 static void
491 do_parse_base_type(struct ovs_cmdl_context *ctx)
492 {
493 struct ovsdb_base_type base;
494 struct json *json;
495
496 json = unbox_json(parse_json(ctx->argv[1]));
497 check_ovsdb_error(ovsdb_base_type_from_json(&base, json));
498 json_destroy(json);
499 print_and_free_json(ovsdb_base_type_to_json(&base));
500 ovsdb_base_type_destroy(&base);
501 }
502
503 static void
504 do_parse_type(struct ovs_cmdl_context *ctx)
505 {
506 struct ovsdb_type type;
507 struct json *json;
508
509 json = unbox_json(parse_json(ctx->argv[1]));
510 check_ovsdb_error(ovsdb_type_from_json(&type, json));
511 json_destroy(json);
512 print_and_free_json(ovsdb_type_to_json(&type));
513 ovsdb_type_destroy(&type);
514 }
515
516 static void
517 do_parse_atoms(struct ovs_cmdl_context *ctx)
518 {
519 struct ovsdb_base_type base;
520 struct json *json;
521 int i;
522
523 json = unbox_json(parse_json(ctx->argv[1]));
524 check_ovsdb_error(ovsdb_base_type_from_json(&base, json));
525 json_destroy(json);
526
527 for (i = 2; i < ctx->argc; i++) {
528 struct ovsdb_error *error;
529 union ovsdb_atom atom;
530
531 json = unbox_json(parse_json(ctx->argv[i]));
532 error = ovsdb_atom_from_json(&atom, &base, json, NULL);
533 json_destroy(json);
534
535 if (error) {
536 print_and_free_ovsdb_error(error);
537 } else {
538 print_and_free_json(ovsdb_atom_to_json(&atom, base.type));
539 ovsdb_atom_destroy(&atom, base.type);
540 }
541 }
542 ovsdb_base_type_destroy(&base);
543 }
544
545 static void
546 do_parse_atom_strings(struct ovs_cmdl_context *ctx)
547 {
548 struct ovsdb_base_type base;
549 struct json *json;
550 int i;
551
552 json = unbox_json(parse_json(ctx->argv[1]));
553 check_ovsdb_error(ovsdb_base_type_from_json(&base, json));
554 json_destroy(json);
555
556 for (i = 2; i < ctx->argc; i++) {
557 union ovsdb_atom atom, *range_end_atom = NULL;
558 struct ds out;
559
560 die_if_error(ovsdb_atom_from_string(&atom, &range_end_atom, &base,
561 ctx->argv[i], NULL));
562
563 ds_init(&out);
564 ovsdb_atom_to_string(&atom, base.type, &out);
565 if (range_end_atom) {
566 struct ds range_end_ds;
567 ds_init(&range_end_ds);
568 ovsdb_atom_to_string(range_end_atom, base.type, &range_end_ds);
569 ds_put_char(&out, '-');
570 ds_put_cstr(&out, ds_cstr(&range_end_ds));;
571 ds_destroy(&range_end_ds);
572 }
573 puts(ds_cstr(&out));
574 ds_destroy(&out);
575
576 ovsdb_atom_destroy(&atom, base.type);
577 if (range_end_atom) {
578 ovsdb_atom_destroy(range_end_atom, base.type);
579 }
580 }
581 ovsdb_base_type_destroy(&base);
582 }
583
584 static void
585 do_parse_data__(int argc, char *argv[],
586 struct ovsdb_error *
587 (*parse)(struct ovsdb_datum *datum,
588 const struct ovsdb_type *type,
589 const struct json *json,
590 struct ovsdb_symbol_table *symtab))
591 {
592 struct ovsdb_type type;
593 struct json *json;
594 int i;
595
596 json = unbox_json(parse_json(argv[1]));
597 check_ovsdb_error(ovsdb_type_from_json(&type, json));
598 json_destroy(json);
599
600 for (i = 2; i < argc; i++) {
601 struct ovsdb_datum datum;
602
603 json = unbox_json(parse_json(argv[i]));
604 check_ovsdb_error(parse(&datum, &type, json, NULL));
605 json_destroy(json);
606
607 print_and_free_json(ovsdb_datum_to_json(&datum, &type));
608
609 ovsdb_datum_destroy(&datum, &type);
610 }
611 ovsdb_type_destroy(&type);
612 }
613
614 static void
615 do_parse_data(struct ovs_cmdl_context *ctx)
616 {
617 do_parse_data__(ctx->argc, ctx->argv, ovsdb_datum_from_json);
618 }
619
620 static void
621 do_parse_data_strings(struct ovs_cmdl_context *ctx)
622 {
623 struct ovsdb_type type;
624 struct json *json;
625 int i;
626
627 json = unbox_json(parse_json(ctx->argv[1]));
628 check_ovsdb_error(ovsdb_type_from_json(&type, json));
629 json_destroy(json);
630
631 for (i = 2; i < ctx->argc; i++) {
632 struct ovsdb_datum datum;
633 struct ds out;
634
635 die_if_error(ovsdb_datum_from_string(&datum, &type, ctx->argv[i], NULL));
636
637 ds_init(&out);
638 ovsdb_datum_to_string(&datum, &type, &out);
639 puts(ds_cstr(&out));
640 ds_destroy(&out);
641
642 ovsdb_datum_destroy(&datum, &type);
643 }
644 ovsdb_type_destroy(&type);
645 }
646
647 static enum ovsdb_atomic_type compare_atoms_atomic_type;
648
649 static int
650 compare_atoms(const void *a_, const void *b_)
651 {
652 const union ovsdb_atom *a = a_;
653 const union ovsdb_atom *b = b_;
654
655 return ovsdb_atom_compare_3way(a, b, compare_atoms_atomic_type);
656 }
657
658 static void
659 do_sort_atoms(struct ovs_cmdl_context *ctx)
660 {
661 struct ovsdb_base_type base;
662 union ovsdb_atom *atoms;
663 struct json *json, **json_atoms;
664 size_t n_atoms;
665 int i;
666
667 json = unbox_json(parse_json(ctx->argv[1]));
668 check_ovsdb_error(ovsdb_base_type_from_json(&base, json));
669 json_destroy(json);
670
671 json = unbox_json(parse_json(ctx->argv[2]));
672 if (json->type != JSON_ARRAY) {
673 ovs_fatal(0, "second argument must be array");
674 }
675
676 /* Convert JSON atoms to internal representation. */
677 n_atoms = json->u.array.n;
678 atoms = xmalloc(n_atoms * sizeof *atoms);
679 for (i = 0; i < n_atoms; i++) {
680 check_ovsdb_error(ovsdb_atom_from_json(&atoms[i], &base,
681 json->u.array.elems[i], NULL));
682 }
683 json_destroy(json);
684
685 /* Sort atoms. */
686 compare_atoms_atomic_type = base.type;
687 qsort(atoms, n_atoms, sizeof *atoms, compare_atoms);
688
689 /* Convert internal representation back to JSON. */
690 json_atoms = xmalloc(n_atoms * sizeof *json_atoms);
691 for (i = 0; i < n_atoms; i++) {
692 json_atoms[i] = ovsdb_atom_to_json(&atoms[i], base.type);
693 ovsdb_atom_destroy(&atoms[i], base.type);
694 }
695 print_and_free_json(json_array_create(json_atoms, n_atoms));
696 free(atoms);
697 ovsdb_base_type_destroy(&base);
698 }
699
700 static void
701 do_parse_column(struct ovs_cmdl_context *ctx)
702 {
703 struct ovsdb_column *column;
704 struct json *json;
705
706 json = parse_json(ctx->argv[2]);
707 check_ovsdb_error(ovsdb_column_from_json(json, ctx->argv[1], &column));
708 json_destroy(json);
709 print_and_free_json(ovsdb_column_to_json(column));
710 ovsdb_column_destroy(column);
711 }
712
713 static void
714 do_parse_table(struct ovs_cmdl_context *ctx)
715 {
716 struct ovsdb_table_schema *ts;
717 bool default_is_root;
718 struct json *json;
719
720 default_is_root = ctx->argc > 3 && !strcmp(ctx->argv[3], "true");
721
722 json = parse_json(ctx->argv[2]);
723 check_ovsdb_error(ovsdb_table_schema_from_json(json, ctx->argv[1], &ts));
724 json_destroy(json);
725 print_and_free_json(ovsdb_table_schema_to_json(ts, default_is_root));
726 ovsdb_table_schema_destroy(ts);
727 }
728
729 static void
730 do_parse_rows(struct ovs_cmdl_context *ctx)
731 {
732 struct ovsdb_column_set all_columns;
733 struct ovsdb_table_schema *ts;
734 struct ovsdb_table *table;
735 struct json *json;
736 int i;
737
738 json = unbox_json(parse_json(ctx->argv[1]));
739 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
740 json_destroy(json);
741
742 table = ovsdb_table_create(ts);
743 ovsdb_column_set_init(&all_columns);
744 ovsdb_column_set_add_all(&all_columns, table);
745
746 for (i = 2; i < ctx->argc; i++) {
747 struct ovsdb_column_set columns;
748 struct ovsdb_row *row;
749
750 ovsdb_column_set_init(&columns);
751 row = ovsdb_row_create(table);
752
753 json = unbox_json(parse_json(ctx->argv[i]));
754 check_ovsdb_error(ovsdb_row_from_json(row, json, NULL, &columns));
755 json_destroy(json);
756
757 print_and_free_json(ovsdb_row_to_json(row, &all_columns));
758
759 if (columns.n_columns) {
760 struct svec names;
761 size_t j;
762 char *s;
763
764 svec_init(&names);
765 for (j = 0; j < columns.n_columns; j++) {
766 svec_add(&names, columns.columns[j]->name);
767 }
768 svec_sort(&names);
769 s = svec_join(&names, ", ", "");
770 puts(s);
771 free(s);
772 svec_destroy(&names);
773 } else {
774 printf("<none>\n");
775 }
776
777 ovsdb_column_set_destroy(&columns);
778 ovsdb_row_destroy(row);
779 }
780
781 ovsdb_column_set_destroy(&all_columns);
782 ovsdb_table_destroy(table); /* Also destroys 'ts'. */
783 }
784
785 static void
786 do_compare_rows(struct ovs_cmdl_context *ctx)
787 {
788 struct ovsdb_column_set all_columns;
789 struct ovsdb_table_schema *ts;
790 struct ovsdb_table *table;
791 struct ovsdb_row **rows;
792 struct json *json;
793 char **names;
794 int n_rows;
795 int i, j;
796
797 json = unbox_json(parse_json(ctx->argv[1]));
798 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
799 json_destroy(json);
800
801 table = ovsdb_table_create(ts);
802 ovsdb_column_set_init(&all_columns);
803 ovsdb_column_set_add_all(&all_columns, table);
804
805 n_rows = ctx->argc - 2;
806 rows = xmalloc(sizeof *rows * n_rows);
807 names = xmalloc(sizeof *names * n_rows);
808 for (i = 0; i < n_rows; i++) {
809 rows[i] = ovsdb_row_create(table);
810
811 json = parse_json(ctx->argv[i + 2]);
812 if (json->type != JSON_ARRAY || json->u.array.n != 2
813 || json->u.array.elems[0]->type != JSON_STRING) {
814 ovs_fatal(0, "\"%s\" does not have expected form "
815 "[\"name\", {data}]", ctx->argv[i]);
816 }
817 names[i] = xstrdup(json->u.array.elems[0]->u.string);
818 check_ovsdb_error(ovsdb_row_from_json(rows[i], json->u.array.elems[1],
819 NULL, NULL));
820 json_destroy(json);
821 }
822 for (i = 0; i < n_rows; i++) {
823 uint32_t i_hash = ovsdb_row_hash_columns(rows[i], &all_columns, 0);
824 for (j = i + 1; j < n_rows; j++) {
825 uint32_t j_hash = ovsdb_row_hash_columns(rows[j], &all_columns, 0);
826 if (ovsdb_row_equal_columns(rows[i], rows[j], &all_columns)) {
827 printf("%s == %s\n", names[i], names[j]);
828 if (i_hash != j_hash) {
829 printf("but hash(%s) != hash(%s)\n", names[i], names[j]);
830 abort();
831 }
832 } else if (i_hash == j_hash) {
833 printf("hash(%s) == hash(%s)\n", names[i], names[j]);
834 }
835 }
836 }
837 for (i = 0; i < n_rows; i++) {
838 ovsdb_row_destroy(rows[i]);
839 free(names[i]);
840 }
841 free(rows);
842 free(names);
843
844 ovsdb_column_set_destroy(&all_columns);
845 ovsdb_table_destroy(table); /* Also destroys 'ts'. */
846 }
847
848 static void
849 do_parse_conditions(struct ovs_cmdl_context *ctx)
850 {
851 struct ovsdb_table_schema *ts;
852 struct json *json;
853 int exit_code = 0;
854 int i;
855
856 json = unbox_json(parse_json(ctx->argv[1]));
857 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
858 json_destroy(json);
859
860 for (i = 2; i < ctx->argc; i++) {
861 struct ovsdb_condition cnd;
862 struct ovsdb_error *error;
863
864 json = parse_json(ctx->argv[i]);
865 error = ovsdb_condition_from_json(ts, json, NULL, &cnd);
866 if (!error) {
867 print_and_free_json(ovsdb_condition_to_json(&cnd));
868 } else {
869 char *s = ovsdb_error_to_string(error);
870 ovs_error(0, "%s", s);
871 free(s);
872 ovsdb_error_destroy(error);
873 exit_code = 1;
874 }
875 json_destroy(json);
876
877 ovsdb_condition_destroy(&cnd);
878 }
879 ovsdb_table_schema_destroy(ts);
880
881 exit(exit_code);
882 }
883
884 #define OVSDB_CONDITION_EVERY 0
885 #define OVSDB_CONDITION_ANY 1
886
887 static void
888 do_evaluate_condition__(struct ovs_cmdl_context *ctx, int mode)
889 {
890 struct ovsdb_table_schema *ts;
891 struct ovsdb_table *table;
892 struct ovsdb_condition *conditions;
893 size_t n_conditions;
894 struct ovsdb_row **rows;
895 size_t n_rows;
896 struct json *json;
897 size_t i, j;
898
899 /* Parse table schema, create table. */
900 json = unbox_json(parse_json(ctx->argv[1]));
901 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
902 json_destroy(json);
903
904 table = ovsdb_table_create(ts);
905
906 /* Parse conditions. */
907 json = parse_json(ctx->argv[2]);
908 if (json->type != JSON_ARRAY) {
909 ovs_fatal(0, "CONDITION argument is not JSON array");
910 }
911 n_conditions = json->u.array.n;
912 conditions = xmalloc(n_conditions * sizeof *conditions);
913 for (i = 0; i < n_conditions; i++) {
914 check_ovsdb_error(ovsdb_condition_from_json(ts, json->u.array.elems[i],
915 NULL, &conditions[i]));
916 }
917 json_destroy(json);
918
919 /* Parse rows. */
920 json = parse_json(ctx->argv[3]);
921 if (json->type != JSON_ARRAY) {
922 ovs_fatal(0, "ROW argument is not JSON array");
923 }
924 n_rows = json->u.array.n;
925 rows = xmalloc(n_rows * sizeof *rows);
926 for (i = 0; i < n_rows; i++) {
927 rows[i] = ovsdb_row_create(table);
928 check_ovsdb_error(ovsdb_row_from_json(rows[i], json->u.array.elems[i],
929 NULL, NULL));
930 }
931 json_destroy(json);
932
933 for (i = 0; i < n_conditions; i++) {
934 printf("condition %2"PRIuSIZE":", i);
935 for (j = 0; j < n_rows; j++) {
936 bool result;
937 if (mode == OVSDB_CONDITION_EVERY) {
938 result = ovsdb_condition_match_every_clause(rows[j],
939 &conditions[i]);
940 } else {
941 result = ovsdb_condition_match_any_clause(rows[j]->fields,
942 &conditions[i],
943 NULL);
944 }
945 if (j % 5 == 0) {
946 putchar(' ');
947 }
948 putchar(result ? 'T' : '-');
949 }
950 printf("\n");
951 }
952
953 for (i = 0; i < n_conditions; i++) {
954 ovsdb_condition_destroy(&conditions[i]);
955 }
956 free(conditions);
957 for (i = 0; i < n_rows; i++) {
958 ovsdb_row_destroy(rows[i]);
959 }
960 free(rows);
961 ovsdb_table_destroy(table); /* Also destroys 'ts'. */
962 }
963
964 static void
965 do_evaluate_conditions(struct ovs_cmdl_context *ctx)
966 {
967 do_evaluate_condition__(ctx, OVSDB_CONDITION_EVERY);
968 }
969
970 static void
971 do_evaluate_conditions_any(struct ovs_cmdl_context *ctx)
972 {
973 do_evaluate_condition__(ctx, OVSDB_CONDITION_ANY);
974 }
975
976 static void
977 do_compare_conditions(struct ovs_cmdl_context *ctx)
978 {
979 struct ovsdb_table_schema *ts;
980 struct ovsdb_table *table;
981 struct ovsdb_condition *conditions;
982 size_t n_conditions;
983 struct json *json;
984 size_t i;
985
986 /* Parse table schema, create table. */
987 json = unbox_json(parse_json(ctx->argv[1]));
988 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
989 json_destroy(json);
990
991 table = ovsdb_table_create(ts);
992
993 /* Parse conditions. */
994 json = parse_json(ctx->argv[2]);
995 if (json->type != JSON_ARRAY) {
996 ovs_fatal(0, "CONDITION argument is not JSON array");
997 }
998 n_conditions = json->u.array.n;
999 conditions = xmalloc(n_conditions * sizeof *conditions);
1000
1001 for (i = 0; i < n_conditions; i++) {
1002 check_ovsdb_error(ovsdb_condition_from_json(ts, json->u.array.elems[i],
1003 NULL, &conditions[i]));
1004 }
1005 json_destroy(json);
1006
1007 for (i = 0; i < n_conditions - 1; i++) {
1008 int res = ovsdb_condition_cmp_3way(&conditions[i], &conditions[i + 1]);
1009 printf("condition %"PRIuSIZE"-%"PRIuSIZE": %d\n", i, i + 1, res);
1010 }
1011
1012 for (i = 0; i < n_conditions; i++) {
1013 ovsdb_condition_destroy(&conditions[i]);
1014 }
1015 free(conditions);
1016 ovsdb_table_destroy(table); /* Also destroys 'ts'. */
1017 }
1018
1019 static void
1020 do_parse_mutations(struct ovs_cmdl_context *ctx)
1021 {
1022 struct ovsdb_table_schema *ts;
1023 struct json *json;
1024 int exit_code = 0;
1025 int i;
1026
1027 json = unbox_json(parse_json(ctx->argv[1]));
1028 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
1029 json_destroy(json);
1030
1031 for (i = 2; i < ctx->argc; i++) {
1032 struct ovsdb_mutation_set set;
1033 struct ovsdb_error *error;
1034
1035 json = parse_json(ctx->argv[i]);
1036 error = ovsdb_mutation_set_from_json(ts, json, NULL, &set);
1037 if (!error) {
1038 print_and_free_json(ovsdb_mutation_set_to_json(&set));
1039 } else {
1040 char *s = ovsdb_error_to_string(error);
1041 ovs_error(0, "%s", s);
1042 free(s);
1043 ovsdb_error_destroy(error);
1044 exit_code = 1;
1045 }
1046 json_destroy(json);
1047
1048 ovsdb_mutation_set_destroy(&set);
1049 }
1050 ovsdb_table_schema_destroy(ts);
1051
1052 exit(exit_code);
1053 }
1054
1055 static void
1056 do_execute_mutations(struct ovs_cmdl_context *ctx)
1057 {
1058 struct ovsdb_table_schema *ts;
1059 struct ovsdb_table *table;
1060 struct ovsdb_mutation_set *sets;
1061 size_t n_sets;
1062 struct ovsdb_row **rows;
1063 size_t n_rows;
1064 struct json *json;
1065 size_t i, j;
1066
1067 /* Parse table schema, create table. */
1068 json = unbox_json(parse_json(ctx->argv[1]));
1069 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
1070 json_destroy(json);
1071
1072 table = ovsdb_table_create(ts);
1073
1074 /* Parse mutations. */
1075 json = parse_json(ctx->argv[2]);
1076 if (json->type != JSON_ARRAY) {
1077 ovs_fatal(0, "MUTATION argument is not JSON array");
1078 }
1079 n_sets = json->u.array.n;
1080 sets = xmalloc(n_sets * sizeof *sets);
1081 for (i = 0; i < n_sets; i++) {
1082 check_ovsdb_error(ovsdb_mutation_set_from_json(ts,
1083 json->u.array.elems[i],
1084 NULL, &sets[i]));
1085 }
1086 json_destroy(json);
1087
1088 /* Parse rows. */
1089 json = parse_json(ctx->argv[3]);
1090 if (json->type != JSON_ARRAY) {
1091 ovs_fatal(0, "ROW argument is not JSON array");
1092 }
1093 n_rows = json->u.array.n;
1094 rows = xmalloc(n_rows * sizeof *rows);
1095 for (i = 0; i < n_rows; i++) {
1096 rows[i] = ovsdb_row_create(table);
1097 check_ovsdb_error(ovsdb_row_from_json(rows[i], json->u.array.elems[i],
1098 NULL, NULL));
1099 }
1100 json_destroy(json);
1101
1102 for (i = 0; i < n_sets; i++) {
1103 printf("mutation %2"PRIuSIZE":\n", i);
1104 for (j = 0; j < n_rows; j++) {
1105 struct ovsdb_error *error;
1106 struct ovsdb_row *row;
1107
1108 row = ovsdb_row_clone(rows[j]);
1109 error = ovsdb_mutation_set_execute(row, &sets[i]);
1110
1111 printf("row %"PRIuSIZE": ", j);
1112 if (error) {
1113 print_and_free_ovsdb_error(error);
1114 } else {
1115 struct ovsdb_column_set columns;
1116 struct shash_node *node;
1117
1118 ovsdb_column_set_init(&columns);
1119 SHASH_FOR_EACH (node, &ts->columns) {
1120 struct ovsdb_column *c = node->data;
1121 if (!ovsdb_datum_equals(&row->fields[c->index],
1122 &rows[j]->fields[c->index],
1123 &c->type)) {
1124 ovsdb_column_set_add(&columns, c);
1125 }
1126 }
1127 if (columns.n_columns) {
1128 print_and_free_json(ovsdb_row_to_json(row, &columns));
1129 } else {
1130 printf("no change\n");
1131 }
1132 ovsdb_column_set_destroy(&columns);
1133 }
1134 ovsdb_row_destroy(row);
1135 }
1136 printf("\n");
1137 }
1138
1139 for (i = 0; i < n_sets; i++) {
1140 ovsdb_mutation_set_destroy(&sets[i]);
1141 }
1142 free(sets);
1143 for (i = 0; i < n_rows; i++) {
1144 ovsdb_row_destroy(rows[i]);
1145 }
1146 free(rows);
1147 ovsdb_table_destroy(table); /* Also destroys 'ts'. */
1148 }
1149
1150 /* Inserts a row, without bothering to update metadata such as refcounts. */
1151 static void
1152 put_row(struct ovsdb_table *table, struct ovsdb_row *row)
1153 {
1154 const struct uuid *uuid = ovsdb_row_get_uuid(row);
1155 if (!ovsdb_table_get_row(table, uuid)) {
1156 hmap_insert(&table->rows, &row->hmap_node, uuid_hash(uuid));
1157 }
1158 }
1159
1160 struct do_query_cbdata {
1161 struct uuid *row_uuids;
1162 int *counts;
1163 size_t n_rows;
1164 };
1165
1166 static bool
1167 do_query_cb(const struct ovsdb_row *row, void *cbdata_)
1168 {
1169 struct do_query_cbdata *cbdata = cbdata_;
1170 size_t i;
1171
1172 for (i = 0; i < cbdata->n_rows; i++) {
1173 if (uuid_equals(ovsdb_row_get_uuid(row), &cbdata->row_uuids[i])) {
1174 cbdata->counts[i]++;
1175 }
1176 }
1177
1178 return true;
1179 }
1180
1181 static void
1182 do_query(struct ovs_cmdl_context *ctx)
1183 {
1184 struct do_query_cbdata cbdata;
1185 struct ovsdb_table_schema *ts;
1186 struct ovsdb_table *table;
1187 struct json *json;
1188 int exit_code = 0;
1189 size_t i;
1190
1191 /* Parse table schema, create table. */
1192 json = unbox_json(parse_json(ctx->argv[1]));
1193 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
1194 json_destroy(json);
1195
1196 table = ovsdb_table_create(ts);
1197
1198 /* Parse rows, add to table. */
1199 json = parse_json(ctx->argv[2]);
1200 if (json->type != JSON_ARRAY) {
1201 ovs_fatal(0, "ROW argument is not JSON array");
1202 }
1203 cbdata.n_rows = json->u.array.n;
1204 cbdata.row_uuids = xmalloc(cbdata.n_rows * sizeof *cbdata.row_uuids);
1205 cbdata.counts = xmalloc(cbdata.n_rows * sizeof *cbdata.counts);
1206 for (i = 0; i < cbdata.n_rows; i++) {
1207 struct ovsdb_row *row = ovsdb_row_create(table);
1208 uuid_generate(ovsdb_row_get_uuid_rw(row));
1209 check_ovsdb_error(ovsdb_row_from_json(row, json->u.array.elems[i],
1210 NULL, NULL));
1211 if (ovsdb_table_get_row(table, ovsdb_row_get_uuid(row))) {
1212 ovs_fatal(0, "duplicate UUID "UUID_FMT" in table",
1213 UUID_ARGS(ovsdb_row_get_uuid(row)));
1214 }
1215 cbdata.row_uuids[i] = *ovsdb_row_get_uuid(row);
1216 put_row(table, row);
1217 }
1218 json_destroy(json);
1219
1220 /* Parse conditions and execute queries. */
1221 json = parse_json(ctx->argv[3]);
1222 if (json->type != JSON_ARRAY) {
1223 ovs_fatal(0, "CONDITION argument is not JSON array");
1224 }
1225 for (i = 0; i < json->u.array.n; i++) {
1226 struct ovsdb_condition cnd;
1227 size_t j;
1228
1229 check_ovsdb_error(ovsdb_condition_from_json(ts, json->u.array.elems[i],
1230 NULL, &cnd));
1231
1232 memset(cbdata.counts, 0, cbdata.n_rows * sizeof *cbdata.counts);
1233 ovsdb_query(table, &cnd, do_query_cb, &cbdata);
1234
1235 printf("query %2"PRIuSIZE":", i);
1236 for (j = 0; j < cbdata.n_rows; j++) {
1237 if (j % 5 == 0) {
1238 putchar(' ');
1239 }
1240 if (cbdata.counts[j]) {
1241 printf("%d", cbdata.counts[j]);
1242 if (cbdata.counts[j] > 1) {
1243 /* Dup! */
1244 exit_code = 1;
1245 }
1246 } else {
1247 putchar('-');
1248 }
1249 }
1250 putchar('\n');
1251
1252 ovsdb_condition_destroy(&cnd);
1253 }
1254 json_destroy(json);
1255
1256 ovsdb_table_destroy(table); /* Also destroys 'ts'. */
1257
1258 exit(exit_code);
1259 }
1260
1261 struct do_query_distinct_class {
1262 struct ovsdb_row *example;
1263 int count;
1264 };
1265
1266 struct do_query_distinct_row {
1267 struct uuid uuid;
1268 struct do_query_distinct_class *class;
1269 };
1270
1271 static void
1272 do_query_distinct(struct ovs_cmdl_context *ctx)
1273 {
1274 struct ovsdb_column_set columns;
1275 struct ovsdb_table_schema *ts;
1276 struct ovsdb_table *table;
1277 struct do_query_distinct_row *rows;
1278 size_t n_rows;
1279 struct do_query_distinct_class *classes;
1280 size_t n_classes;
1281 struct json *json;
1282 int exit_code = 0;
1283 size_t i;
1284
1285 /* Parse table schema, create table. */
1286 json = unbox_json(parse_json(ctx->argv[1]));
1287 check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
1288 json_destroy(json);
1289
1290 table = ovsdb_table_create(ts);
1291
1292 /* Parse column set. */
1293 json = parse_json(ctx->argv[4]);
1294 check_ovsdb_error(ovsdb_column_set_from_json(json, table->schema,
1295 &columns));
1296 json_destroy(json);
1297
1298 /* Parse rows, add to table. */
1299 json = parse_json(ctx->argv[2]);
1300 if (json->type != JSON_ARRAY) {
1301 ovs_fatal(0, "ROW argument is not JSON array");
1302 }
1303 n_rows = json->u.array.n;
1304 rows = xmalloc(n_rows * sizeof *rows);
1305 classes = xmalloc(n_rows * sizeof *classes);
1306 n_classes = 0;
1307 for (i = 0; i < n_rows; i++) {
1308 struct ovsdb_row *row;
1309 size_t j;
1310
1311 /* Parse row. */
1312 row = ovsdb_row_create(table);
1313 uuid_generate(ovsdb_row_get_uuid_rw(row));
1314 check_ovsdb_error(ovsdb_row_from_json(row, json->u.array.elems[i],
1315 NULL, NULL));
1316
1317 /* Initialize row and find equivalence class. */
1318 rows[i].uuid = *ovsdb_row_get_uuid(row);
1319 rows[i].class = NULL;
1320 for (j = 0; j < n_classes; j++) {
1321 if (ovsdb_row_equal_columns(row, classes[j].example, &columns)) {
1322 rows[i].class = &classes[j];
1323 break;
1324 }
1325 }
1326 if (!rows[i].class) {
1327 rows[i].class = &classes[n_classes];
1328 classes[n_classes].example = ovsdb_row_clone(row);
1329 n_classes++;
1330 }
1331
1332 /* Add row to table. */
1333 if (ovsdb_table_get_row(table, ovsdb_row_get_uuid(row))) {
1334 ovs_fatal(0, "duplicate UUID "UUID_FMT" in table",
1335 UUID_ARGS(ovsdb_row_get_uuid(row)));
1336 }
1337 put_row(table, row);
1338
1339 }
1340 json_destroy(json);
1341
1342 /* Parse conditions and execute queries. */
1343 json = parse_json(ctx->argv[3]);
1344 if (json->type != JSON_ARRAY) {
1345 ovs_fatal(0, "CONDITION argument is not JSON array");
1346 }
1347 for (i = 0; i < json->u.array.n; i++) {
1348 struct ovsdb_row_set results;
1349 struct ovsdb_condition cnd;
1350 size_t j;
1351
1352 check_ovsdb_error(ovsdb_condition_from_json(ts, json->u.array.elems[i],
1353 NULL, &cnd));
1354
1355 for (j = 0; j < n_classes; j++) {
1356 classes[j].count = 0;
1357 }
1358 ovsdb_row_set_init(&results);
1359 ovsdb_query_distinct(table, &cnd, &columns, &results);
1360 for (j = 0; j < results.n_rows; j++) {
1361 size_t k;
1362
1363 for (k = 0; k < n_rows; k++) {
1364 if (uuid_equals(ovsdb_row_get_uuid(results.rows[j]),
1365 &rows[k].uuid)) {
1366 rows[k].class->count++;
1367 }
1368 }
1369 }
1370 ovsdb_row_set_destroy(&results);
1371
1372 printf("query %2"PRIuSIZE":", i);
1373 for (j = 0; j < n_rows; j++) {
1374 int count = rows[j].class->count;
1375
1376 if (j % 5 == 0) {
1377 putchar(' ');
1378 }
1379 if (count > 1) {
1380 /* Dup! */
1381 printf("%d", count);
1382 exit_code = 1;
1383 } else if (count == 1) {
1384 putchar("abcdefghijklmnopqrstuvwxyz"[rows[j].class - classes]);
1385 } else {
1386 putchar('-');
1387 }
1388 }
1389 putchar('\n');
1390
1391 ovsdb_condition_destroy(&cnd);
1392 }
1393 json_destroy(json);
1394
1395 for (i = 0; i < n_classes; i++) {
1396 ovsdb_row_destroy(classes[i].example);
1397 }
1398
1399 ovsdb_table_destroy(table); /* Also destroys 'ts'. */
1400
1401 free(rows);
1402 free(classes);
1403 exit(exit_code);
1404 }
1405
1406 static void
1407 do_parse_schema(struct ovs_cmdl_context *ctx)
1408 {
1409 struct ovsdb_schema *schema;
1410 struct json *json;
1411
1412 json = parse_json(ctx->argv[1]);
1413 check_ovsdb_error(ovsdb_schema_from_json(json, &schema));
1414 json_destroy(json);
1415 print_and_free_json(ovsdb_schema_to_json(schema));
1416 ovsdb_schema_destroy(schema);
1417 }
1418
1419 static void
1420 do_execute__(struct ovs_cmdl_context *ctx, bool ro)
1421 {
1422 struct ovsdb_schema *schema;
1423 struct json *json;
1424 struct ovsdb *db;
1425 int i;
1426
1427 /* Create database. */
1428 json = parse_json(ctx->argv[1]);
1429 check_ovsdb_error(ovsdb_schema_from_json(json, &schema));
1430 json_destroy(json);
1431 db = ovsdb_create(schema);
1432
1433 for (i = 2; i < ctx->argc; i++) {
1434 struct json *params, *result;
1435 char *s;
1436
1437 params = parse_json(ctx->argv[i]);
1438 result = ovsdb_execute(db, NULL, params, ro, 0, NULL);
1439 s = json_to_string(result, JSSF_SORT);
1440 printf("%s\n", s);
1441 free(s);
1442 json_destroy(params);
1443 json_destroy(result);
1444 }
1445
1446 ovsdb_destroy(db);
1447 }
1448
1449 static void
1450 do_execute_ro(struct ovs_cmdl_context *ctx)
1451 {
1452 do_execute__(ctx, true);
1453 }
1454
1455 static void
1456 do_execute(struct ovs_cmdl_context *ctx)
1457 {
1458 do_execute__(ctx, false);
1459 }
1460
1461 struct test_trigger {
1462 struct ovsdb_trigger trigger;
1463 int number;
1464 };
1465
1466 static void
1467 do_trigger_dump(struct test_trigger *t, long long int now, const char *title)
1468 {
1469 struct json *result;
1470 char *s;
1471
1472 result = ovsdb_trigger_steal_result(&t->trigger);
1473 s = json_to_string(result, JSSF_SORT);
1474 printf("t=%lld: trigger %d (%s): %s\n", now, t->number, title, s);
1475 free(s);
1476 json_destroy(result);
1477 ovsdb_trigger_destroy(&t->trigger);
1478 free(t);
1479 }
1480
1481 static void
1482 do_trigger(struct ovs_cmdl_context *ctx)
1483 {
1484 struct ovsdb_schema *schema;
1485 struct ovsdb_session session;
1486 struct ovsdb_server server;
1487 struct json *json;
1488 struct ovsdb *db;
1489 long long int now;
1490 int number;
1491 int i;
1492
1493 /* Create database. */
1494 json = parse_json(ctx->argv[1]);
1495 check_ovsdb_error(ovsdb_schema_from_json(json, &schema));
1496 json_destroy(json);
1497 db = ovsdb_create(schema);
1498
1499 ovsdb_server_init(&server);
1500 ovsdb_server_add_db(&server, db);
1501 ovsdb_session_init(&session, &server);
1502
1503 now = 0;
1504 number = 0;
1505 for (i = 2; i < ctx->argc; i++) {
1506 struct json *params = parse_json(ctx->argv[i]);
1507 if (params->type == JSON_ARRAY
1508 && json_array(params)->n == 2
1509 && json_array(params)->elems[0]->type == JSON_STRING
1510 && !strcmp(json_string(json_array(params)->elems[0]), "advance")
1511 && json_array(params)->elems[1]->type == JSON_INTEGER) {
1512 now += json_integer(json_array(params)->elems[1]);
1513 json_destroy(params);
1514 } else {
1515 struct test_trigger *t = xmalloc(sizeof *t);
1516 ovsdb_trigger_init(&session, db, &t->trigger, params, now, false);
1517 t->number = number++;
1518 if (ovsdb_trigger_is_complete(&t->trigger)) {
1519 do_trigger_dump(t, now, "immediate");
1520 } else {
1521 printf("t=%lld: new trigger %d\n", now, t->number);
1522 }
1523 }
1524
1525 ovsdb_trigger_run(db, now);
1526 while (!ovs_list_is_empty(&session.completions)) {
1527 do_trigger_dump(CONTAINER_OF(ovs_list_pop_front(&session.completions),
1528 struct test_trigger, trigger.node),
1529 now, "delayed");
1530 }
1531
1532 ovsdb_trigger_wait(db, now);
1533 poll_immediate_wake();
1534 poll_block();
1535 }
1536
1537 ovsdb_server_destroy(&server);
1538 ovsdb_destroy(db);
1539 }
1540
1541 static void
1542 do_help(struct ovs_cmdl_context *ctx OVS_UNUSED)
1543 {
1544 usage();
1545 }
1546 \f
1547 /* "transact" command. */
1548
1549 static struct ovsdb *do_transact_db;
1550 static struct ovsdb_txn *do_transact_txn;
1551 static struct ovsdb_table *do_transact_table;
1552
1553 static void
1554 do_transact_commit(struct ovs_cmdl_context *ctx OVS_UNUSED)
1555 {
1556 ovsdb_error_destroy(ovsdb_txn_commit(do_transact_txn, false));
1557 do_transact_txn = NULL;
1558 }
1559
1560 static void
1561 do_transact_abort(struct ovs_cmdl_context *ctx OVS_UNUSED)
1562 {
1563 ovsdb_txn_abort(do_transact_txn);
1564 do_transact_txn = NULL;
1565 }
1566
1567 static void
1568 uuid_from_integer(int integer, struct uuid *uuid)
1569 {
1570 uuid_zero(uuid);
1571 uuid->parts[3] = integer;
1572 }
1573
1574 static const struct ovsdb_row *
1575 do_transact_find_row(const char *uuid_string)
1576 {
1577 const struct ovsdb_row *row;
1578 struct uuid uuid;
1579
1580 uuid_from_integer(atoi(uuid_string), &uuid);
1581 row = ovsdb_table_get_row(do_transact_table, &uuid);
1582 if (!row) {
1583 ovs_fatal(0, "table does not contain row with UUID "UUID_FMT,
1584 UUID_ARGS(&uuid));
1585 }
1586 return row;
1587 }
1588
1589 static void
1590 do_transact_set_integer(struct ovsdb_row *row, const char *column_name,
1591 int integer)
1592 {
1593 if (integer != -1) {
1594 const struct ovsdb_column *column;
1595
1596 column = ovsdb_table_schema_get_column(do_transact_table->schema,
1597 column_name);
1598 row->fields[column->index].keys[0].integer = integer;
1599 }
1600 }
1601
1602 static int
1603 do_transact_get_integer(const struct ovsdb_row *row, const char *column_name)
1604 {
1605 const struct ovsdb_column *column;
1606
1607 column = ovsdb_table_schema_get_column(do_transact_table->schema,
1608 column_name);
1609 return row->fields[column->index].keys[0].integer;
1610 }
1611
1612 static void
1613 do_transact_set_i_j(struct ovsdb_row *row,
1614 const char *i_string, const char *j_string)
1615 {
1616 do_transact_set_integer(row, "i", atoi(i_string));
1617 do_transact_set_integer(row, "j", atoi(j_string));
1618 }
1619
1620 static void
1621 do_transact_insert(struct ovs_cmdl_context *ctx)
1622 {
1623 struct ovsdb_row *row;
1624 struct uuid *uuid;
1625
1626 row = ovsdb_row_create(do_transact_table);
1627
1628 /* Set UUID. */
1629 uuid = ovsdb_row_get_uuid_rw(row);
1630 uuid_from_integer(atoi(ctx->argv[1]), uuid);
1631 if (ovsdb_table_get_row(do_transact_table, uuid)) {
1632 ovs_fatal(0, "table already contains row with UUID "UUID_FMT,
1633 UUID_ARGS(uuid));
1634 }
1635
1636 do_transact_set_i_j(row, ctx->argv[2], ctx->argv[3]);
1637
1638 /* Insert row. */
1639 ovsdb_txn_row_insert(do_transact_txn, row);
1640 }
1641
1642 static void
1643 do_transact_delete(struct ovs_cmdl_context *ctx)
1644 {
1645 const struct ovsdb_row *row = do_transact_find_row(ctx->argv[1]);
1646 ovsdb_txn_row_delete(do_transact_txn, row);
1647 }
1648
1649 static void
1650 do_transact_modify(struct ovs_cmdl_context *ctx)
1651 {
1652 const struct ovsdb_row *row_ro;
1653 struct ovsdb_row *row_rw;
1654
1655 row_ro = do_transact_find_row(ctx->argv[1]);
1656 row_rw = ovsdb_txn_row_modify(do_transact_txn, row_ro);
1657 do_transact_set_i_j(row_rw, ctx->argv[2], ctx->argv[3]);
1658 }
1659
1660 static int
1661 compare_rows_by_uuid(const void *a_, const void *b_)
1662 {
1663 struct ovsdb_row *const *ap = a_;
1664 struct ovsdb_row *const *bp = b_;
1665
1666 return uuid_compare_3way(ovsdb_row_get_uuid(*ap), ovsdb_row_get_uuid(*bp));
1667 }
1668
1669 static void
1670 do_transact_print(struct ovs_cmdl_context *ctx OVS_UNUSED)
1671 {
1672 const struct ovsdb_row **rows;
1673 const struct ovsdb_row *row;
1674 size_t n_rows;
1675 size_t i;
1676
1677 n_rows = hmap_count(&do_transact_table->rows);
1678 rows = xmalloc(n_rows * sizeof *rows);
1679 i = 0;
1680 HMAP_FOR_EACH (row, hmap_node, &do_transact_table->rows) {
1681 rows[i++] = row;
1682 }
1683 assert(i == n_rows);
1684
1685 qsort(rows, n_rows, sizeof *rows, compare_rows_by_uuid);
1686
1687 for (i = 0; i < n_rows; i++) {
1688 printf("\n%"PRId32": i=%d, j=%d",
1689 ovsdb_row_get_uuid(rows[i])->parts[3],
1690 do_transact_get_integer(rows[i], "i"),
1691 do_transact_get_integer(rows[i], "j"));
1692 }
1693
1694 free(rows);
1695 }
1696
1697 static void
1698 do_transact(struct ovs_cmdl_context *ctx)
1699 {
1700 static const struct ovs_cmdl_command do_transact_commands[] = {
1701 { "commit", NULL, 0, 0, do_transact_commit, OVS_RO },
1702 { "abort", NULL, 0, 0, do_transact_abort, OVS_RO },
1703 { "insert", NULL, 2, 3, do_transact_insert, OVS_RO },
1704 { "delete", NULL, 1, 1, do_transact_delete, OVS_RO },
1705 { "modify", NULL, 2, 3, do_transact_modify, OVS_RO },
1706 { "print", NULL, 0, 0, do_transact_print, OVS_RO },
1707 { NULL, NULL, 0, 0, NULL, OVS_RO },
1708 };
1709
1710 struct ovsdb_schema *schema;
1711 struct json *json;
1712 int i;
1713
1714 /* Create table. */
1715 json = parse_json("{\"name\": \"testdb\", "
1716 " \"tables\": "
1717 " {\"mytable\": "
1718 " {\"columns\": "
1719 " {\"i\": {\"type\": \"integer\"}, "
1720 " \"j\": {\"type\": \"integer\"}}}}}");
1721 check_ovsdb_error(ovsdb_schema_from_json(json, &schema));
1722 json_destroy(json);
1723 do_transact_db = ovsdb_create(schema);
1724 do_transact_table = ovsdb_get_table(do_transact_db, "mytable");
1725 assert(do_transact_table != NULL);
1726
1727 for (i = 1; i < ctx->argc; i++) {
1728 struct json *command;
1729 size_t n_args;
1730 char **args;
1731 int j;
1732 struct ovs_cmdl_context transact_ctx = { .argc = 0, };
1733
1734 command = parse_json(ctx->argv[i]);
1735 if (command->type != JSON_ARRAY) {
1736 ovs_fatal(0, "transaction %d must be JSON array "
1737 "with at least 1 element", i);
1738 }
1739
1740 n_args = command->u.array.n;
1741 args = xmalloc((n_args + 1) * sizeof *args);
1742 for (j = 0; j < n_args; j++) {
1743 struct json *s = command->u.array.elems[j];
1744 if (s->type != JSON_STRING) {
1745 ovs_fatal(0, "transaction %d argument %d must be JSON string",
1746 i, j);
1747 }
1748 args[j] = xstrdup(json_string(s));
1749 }
1750 args[n_args] = NULL;
1751
1752 if (!do_transact_txn) {
1753 do_transact_txn = ovsdb_txn_create(do_transact_db);
1754 }
1755
1756 for (j = 0; j < n_args; j++) {
1757 if (j) {
1758 putchar(' ');
1759 }
1760 fputs(args[j], stdout);
1761 }
1762 fputs(":", stdout);
1763 transact_ctx.argc = n_args;
1764 transact_ctx.argv = args;
1765 ovs_cmdl_run_command(&transact_ctx, do_transact_commands);
1766 putchar('\n');
1767
1768 for (j = 0; j < n_args; j++) {
1769 free(args[j]);
1770 }
1771 free(args);
1772 json_destroy(command);
1773 }
1774 ovsdb_txn_abort(do_transact_txn);
1775 ovsdb_destroy(do_transact_db); /* Also destroys 'schema'. */
1776 }
1777
1778 static int
1779 compare_link1(const void *a_, const void *b_)
1780 {
1781 const struct idltest_link1 *const *ap = a_;
1782 const struct idltest_link1 *const *bp = b_;
1783 const struct idltest_link1 *a = *ap;
1784 const struct idltest_link1 *b = *bp;
1785
1786 return a->i < b->i ? -1 : a->i > b->i;
1787 }
1788
1789 static void
1790 print_idl_row_updated_simple(const struct idltest_simple *s, int step)
1791 {
1792 size_t i;
1793 bool updated = false;
1794
1795 for (i = 0; i < IDLTEST_SIMPLE_N_COLUMNS; i++) {
1796 if (idltest_simple_is_updated(s, i)) {
1797 if (!updated) {
1798 printf("%03d: updated columns:", step);
1799 updated = true;
1800 }
1801 printf(" %s", idltest_simple_columns[i].name);
1802 }
1803 }
1804 if (updated) {
1805 printf("\n");
1806 }
1807 }
1808
1809 static void
1810 print_idl_row_updated_link1(const struct idltest_link1 *l1, int step)
1811 {
1812 size_t i;
1813 bool updated = false;
1814
1815 for (i = 0; i < IDLTEST_LINK1_N_COLUMNS; i++) {
1816 if (idltest_link1_is_updated(l1, i)) {
1817 if (!updated) {
1818 printf("%03d: updated columns:", step);
1819 updated = true;
1820 }
1821 printf(" %s", idltest_link1_columns[i].name);
1822 }
1823 }
1824 if (updated) {
1825 printf("\n");
1826 }
1827 }
1828
1829 static void
1830 print_idl_row_updated_link2(const struct idltest_link2 *l2, int step)
1831 {
1832 size_t i;
1833 bool updated = false;
1834
1835 for (i = 0; i < IDLTEST_LINK2_N_COLUMNS; i++) {
1836 if (idltest_link2_is_updated(l2, i)) {
1837 if (!updated) {
1838 printf("%03d: updated columns:", step);
1839 updated = true;
1840 }
1841 printf(" %s", idltest_link2_columns[i].name);
1842 }
1843 }
1844 if (updated) {
1845 printf("\n");
1846 }
1847 }
1848
1849 static void
1850 print_idl_row_simple(const struct idltest_simple *s, int step)
1851 {
1852 size_t i;
1853
1854 printf("%03d: i=%"PRId64" r=%g b=%s s=%s u="UUID_FMT" ia=[",
1855 step, s->i, s->r, s->b ? "true" : "false",
1856 s->s, UUID_ARGS(&s->u));
1857 for (i = 0; i < s->n_ia; i++) {
1858 printf("%s%"PRId64, i ? " " : "", s->ia[i]);
1859 }
1860 printf("] ra=[");
1861 for (i = 0; i < s->n_ra; i++) {
1862 printf("%s%g", i ? " " : "", s->ra[i]);
1863 }
1864 printf("] ba=[");
1865 for (i = 0; i < s->n_ba; i++) {
1866 printf("%s%s", i ? " " : "", s->ba[i] ? "true" : "false");
1867 }
1868 printf("] sa=[");
1869 for (i = 0; i < s->n_sa; i++) {
1870 printf("%s%s", i ? " " : "", s->sa[i]);
1871 }
1872 printf("] ua=[");
1873 for (i = 0; i < s->n_ua; i++) {
1874 printf("%s"UUID_FMT, i ? " " : "", UUID_ARGS(&s->ua[i]));
1875 }
1876 printf("] uuid="UUID_FMT"\n", UUID_ARGS(&s->header_.uuid));
1877 print_idl_row_updated_simple(s, step);
1878 }
1879
1880 static void
1881 print_idl_row_link1(const struct idltest_link1 *l1, int step)
1882 {
1883 struct idltest_link1 **links;
1884 size_t i;
1885
1886 printf("%03d: i=%"PRId64" k=", step, l1->i);
1887 if (l1->k) {
1888 printf("%"PRId64, l1->k->i);
1889 }
1890 printf(" ka=[");
1891 links = xmemdup(l1->ka, l1->n_ka * sizeof *l1->ka);
1892 qsort(links, l1->n_ka, sizeof *links, compare_link1);
1893 for (i = 0; i < l1->n_ka; i++) {
1894 printf("%s%"PRId64, i ? " " : "", links[i]->i);
1895 }
1896 free(links);
1897 printf("] l2=");
1898 if (l1->l2) {
1899 printf("%"PRId64, l1->l2->i);
1900 }
1901 printf(" uuid="UUID_FMT"\n", UUID_ARGS(&l1->header_.uuid));
1902 print_idl_row_updated_link1(l1, step);
1903 }
1904
1905 static void
1906 print_idl_row_link2(const struct idltest_link2 *l2, int step)
1907 {
1908 printf("%03d: i=%"PRId64" l1=", step, l2->i);
1909 if (l2->l1) {
1910 printf("%"PRId64, l2->l1->i);
1911 }
1912 printf(" uuid="UUID_FMT"\n", UUID_ARGS(&l2->header_.uuid));
1913 print_idl_row_updated_link2(l2, step);
1914 }
1915
1916 static void
1917 print_idl(struct ovsdb_idl *idl, int step)
1918 {
1919 const struct idltest_simple *s;
1920 const struct idltest_link1 *l1;
1921 const struct idltest_link2 *l2;
1922 int n = 0;
1923
1924 IDLTEST_SIMPLE_FOR_EACH (s, idl) {
1925 print_idl_row_simple(s, step);
1926 n++;
1927 }
1928 IDLTEST_LINK1_FOR_EACH (l1, idl) {
1929 print_idl_row_link1(l1, step);
1930 n++;
1931 }
1932 IDLTEST_LINK2_FOR_EACH (l2, idl) {
1933 print_idl_row_link2(l2, step);
1934 n++;
1935 }
1936 if (!n) {
1937 printf("%03d: empty\n", step);
1938 }
1939 }
1940
1941 static void
1942 print_idl_track(struct ovsdb_idl *idl, int step, unsigned int seqno)
1943 {
1944 const struct idltest_simple *s;
1945 const struct idltest_link1 *l1;
1946 const struct idltest_link2 *l2;
1947 int n = 0;
1948
1949 IDLTEST_SIMPLE_FOR_EACH_TRACKED (s, idl) {
1950 if (idltest_simple_row_get_seqno(s, OVSDB_IDL_CHANGE_DELETE) >= seqno) {
1951 printf("%03d: ##deleted## uuid="UUID_FMT"\n", step, UUID_ARGS(&s->header_.uuid));
1952 } else {
1953 print_idl_row_simple(s, step);
1954 }
1955 n++;
1956 }
1957 IDLTEST_LINK1_FOR_EACH_TRACKED (l1, idl) {
1958 if (idltest_simple_row_get_seqno(s, OVSDB_IDL_CHANGE_DELETE) >= seqno) {
1959 printf("%03d: ##deleted## uuid="UUID_FMT"\n", step, UUID_ARGS(&s->header_.uuid));
1960 } else {
1961 print_idl_row_link1(l1, step);
1962 }
1963 n++;
1964 }
1965 IDLTEST_LINK2_FOR_EACH_TRACKED (l2, idl) {
1966 if (idltest_simple_row_get_seqno(s, OVSDB_IDL_CHANGE_DELETE) >= seqno) {
1967 printf("%03d: ##deleted## uuid="UUID_FMT"\n", step, UUID_ARGS(&s->header_.uuid));
1968 } else {
1969 print_idl_row_link2(l2, step);
1970 }
1971 n++;
1972 }
1973 if (!n) {
1974 printf("%03d: empty\n", step);
1975 }
1976 }
1977
1978 static void
1979 parse_uuids(const struct json *json, struct ovsdb_symbol_table *symtab,
1980 size_t *n)
1981 {
1982 struct uuid uuid;
1983
1984 if (json->type == JSON_STRING && uuid_from_string(&uuid, json->u.string)) {
1985 char *name = xasprintf("#%"PRIuSIZE"#", *n);
1986 fprintf(stderr, "%s = "UUID_FMT"\n", name, UUID_ARGS(&uuid));
1987 ovsdb_symbol_table_put(symtab, name, &uuid, false);
1988 free(name);
1989 *n += 1;
1990 } else if (json->type == JSON_ARRAY) {
1991 size_t i;
1992
1993 for (i = 0; i < json->u.array.n; i++) {
1994 parse_uuids(json->u.array.elems[i], symtab, n);
1995 }
1996 } else if (json->type == JSON_OBJECT) {
1997 const struct shash_node *node;
1998
1999 SHASH_FOR_EACH (node, json_object(json)) {
2000 parse_uuids(node->data, symtab, n);
2001 }
2002 }
2003 }
2004
2005 static void
2006 substitute_uuids(struct json *json, const struct ovsdb_symbol_table *symtab)
2007 {
2008 if (json->type == JSON_STRING) {
2009 const struct ovsdb_symbol *symbol;
2010
2011 symbol = ovsdb_symbol_table_get(symtab, json->u.string);
2012 if (symbol) {
2013 free(json->u.string);
2014 json->u.string = xasprintf(UUID_FMT, UUID_ARGS(&symbol->uuid));
2015 }
2016 } else if (json->type == JSON_ARRAY) {
2017 size_t i;
2018
2019 for (i = 0; i < json->u.array.n; i++) {
2020 substitute_uuids(json->u.array.elems[i], symtab);
2021 }
2022 } else if (json->type == JSON_OBJECT) {
2023 const struct shash_node *node;
2024
2025 SHASH_FOR_EACH (node, json_object(json)) {
2026 substitute_uuids(node->data, symtab);
2027 }
2028 }
2029 }
2030
2031 static const struct idltest_simple *
2032 idltest_find_simple(struct ovsdb_idl *idl, int i)
2033 {
2034 const struct idltest_simple *s;
2035
2036 IDLTEST_SIMPLE_FOR_EACH (s, idl) {
2037 if (s->i == i) {
2038 return s;
2039 }
2040 }
2041 return NULL;
2042 }
2043
2044 static void
2045 idl_set(struct ovsdb_idl *idl, char *commands, int step)
2046 {
2047 char *cmd, *save_ptr1 = NULL;
2048 struct ovsdb_idl_txn *txn;
2049 enum ovsdb_idl_txn_status status;
2050 bool increment = false;
2051
2052 txn = ovsdb_idl_txn_create(idl);
2053 ovsdb_idl_check_consistency(idl);
2054 for (cmd = strtok_r(commands, ",", &save_ptr1); cmd;
2055 cmd = strtok_r(NULL, ",", &save_ptr1)) {
2056 char *save_ptr2 = NULL;
2057 char *name, *arg1, *arg2, *arg3;
2058
2059 name = strtok_r(cmd, " ", &save_ptr2);
2060 arg1 = strtok_r(NULL, " ", &save_ptr2);
2061 arg2 = strtok_r(NULL, " ", &save_ptr2);
2062 arg3 = strtok_r(NULL, " ", &save_ptr2);
2063
2064 if (!strcmp(name, "set")) {
2065 const struct idltest_simple *s;
2066
2067 if (!arg3) {
2068 ovs_fatal(0, "\"set\" command requires 3 arguments");
2069 }
2070
2071 s = idltest_find_simple(idl, atoi(arg1));
2072 if (!s) {
2073 ovs_fatal(0, "\"set\" command asks for nonexistent "
2074 "i=%d", atoi(arg1));
2075 }
2076
2077 if (!strcmp(arg2, "b")) {
2078 idltest_simple_set_b(s, atoi(arg3));
2079 } else if (!strcmp(arg2, "s")) {
2080 idltest_simple_set_s(s, arg3);
2081 } else if (!strcmp(arg2, "u")) {
2082 struct uuid uuid;
2083 if (!uuid_from_string(&uuid, arg3)) {
2084 ovs_fatal(0, "\"%s\" is not a valid UUID", arg3);
2085 }
2086 idltest_simple_set_u(s, uuid);
2087 } else if (!strcmp(arg2, "r")) {
2088 idltest_simple_set_r(s, atof(arg3));
2089 } else {
2090 ovs_fatal(0, "\"set\" command asks for unknown column %s",
2091 arg2);
2092 }
2093 } else if (!strcmp(name, "insert")) {
2094 struct idltest_simple *s;
2095
2096 if (!arg1 || arg2) {
2097 ovs_fatal(0, "\"insert\" command requires 1 argument");
2098 }
2099
2100 s = idltest_simple_insert(txn);
2101 idltest_simple_set_i(s, atoi(arg1));
2102 } else if (!strcmp(name, "delete")) {
2103 const struct idltest_simple *s;
2104
2105 if (!arg1 || arg2) {
2106 ovs_fatal(0, "\"delete\" command requires 1 argument");
2107 }
2108
2109 s = idltest_find_simple(idl, atoi(arg1));
2110 if (!s) {
2111 ovs_fatal(0, "\"delete\" command asks for nonexistent "
2112 "i=%d", atoi(arg1));
2113 }
2114 idltest_simple_delete(s);
2115 } else if (!strcmp(name, "verify")) {
2116 const struct idltest_simple *s;
2117
2118 if (!arg2 || arg3) {
2119 ovs_fatal(0, "\"verify\" command requires 2 arguments");
2120 }
2121
2122 s = idltest_find_simple(idl, atoi(arg1));
2123 if (!s) {
2124 ovs_fatal(0, "\"verify\" command asks for nonexistent "
2125 "i=%d", atoi(arg1));
2126 }
2127
2128 if (!strcmp(arg2, "i")) {
2129 idltest_simple_verify_i(s);
2130 } else if (!strcmp(arg2, "b")) {
2131 idltest_simple_verify_b(s);
2132 } else if (!strcmp(arg2, "s")) {
2133 idltest_simple_verify_s(s);
2134 } else if (!strcmp(arg2, "u")) {
2135 idltest_simple_verify_s(s);
2136 } else if (!strcmp(arg2, "r")) {
2137 idltest_simple_verify_r(s);
2138 } else {
2139 ovs_fatal(0, "\"verify\" command asks for unknown column %s",
2140 arg2);
2141 }
2142 } else if (!strcmp(name, "increment")) {
2143 const struct idltest_simple *s;
2144
2145 if (!arg1 || arg2) {
2146 ovs_fatal(0, "\"increment\" command requires 1 argument");
2147 }
2148
2149 s = idltest_find_simple(idl, atoi(arg1));
2150 if (!s) {
2151 ovs_fatal(0, "\"set\" command asks for nonexistent "
2152 "i=%d", atoi(arg1));
2153 }
2154
2155 ovsdb_idl_txn_increment(txn, &s->header_, &idltest_simple_col_i,
2156 false);
2157 increment = true;
2158 } else if (!strcmp(name, "abort")) {
2159 ovsdb_idl_txn_abort(txn);
2160 ovsdb_idl_check_consistency(idl);
2161 break;
2162 } else if (!strcmp(name, "destroy")) {
2163 printf("%03d: destroy\n", step);
2164 ovsdb_idl_txn_destroy(txn);
2165 ovsdb_idl_check_consistency(idl);
2166 return;
2167 } else {
2168 ovs_fatal(0, "unknown command %s", name);
2169 }
2170 ovsdb_idl_check_consistency(idl);
2171 }
2172
2173 status = ovsdb_idl_txn_commit_block(txn);
2174 printf("%03d: commit, status=%s",
2175 step, ovsdb_idl_txn_status_to_string(status));
2176 if (increment) {
2177 printf(", increment=%"PRId64,
2178 ovsdb_idl_txn_get_increment_new_value(txn));
2179 }
2180 putchar('\n');
2181 ovsdb_idl_txn_destroy(txn);
2182 ovsdb_idl_check_consistency(idl);
2183 }
2184
2185 static const struct ovsdb_idl_table_class *
2186 find_table_class(const char *name)
2187 {
2188 if (!strcmp(name, "simple")) {
2189 return &idltest_table_simple;
2190 } else if (!strcmp(name, "link1")) {
2191 return &idltest_table_link1;
2192 } else if (!strcmp(name, "link2")) {
2193 return &idltest_table_link2;
2194 }
2195 return NULL;
2196 }
2197
2198 static void
2199 parse_simple_json_clause(struct ovsdb_idl_condition *cond,
2200 enum ovsdb_function function,
2201 const char *column, const struct json *arg)
2202 {
2203 if (!strcmp(column, "b")) {
2204 idltest_simple_add_clause_b(cond, function, json_boolean(arg));
2205 } else if (!strcmp(column, "i")) {
2206 idltest_simple_add_clause_i(cond, function, json_integer(arg));
2207 } else if (!strcmp(column, "s")) {
2208 idltest_simple_add_clause_s(cond, function, json_string(arg));
2209 } else if (!strcmp(column, "u")) {
2210 struct uuid uuid;
2211 if (!uuid_from_string(&uuid, json_string(arg))) {
2212 ovs_fatal(0, "\"%s\" is not a valid UUID", json_string(arg));
2213 }
2214 idltest_simple_add_clause_u(cond, function, uuid);
2215 } else if (!strcmp(column, "r")) {
2216 idltest_simple_add_clause_r(cond, function, json_real(arg));
2217 } else {
2218 ovs_fatal(0, "Unsupported columns name %s", column);
2219 }
2220 }
2221
2222 static void
2223 parse_link1_json_clause(struct ovsdb_idl_condition *cond,
2224 enum ovsdb_function function,
2225 const char *column, const struct json *arg)
2226 {
2227 if (!strcmp(column, "i")) {
2228 idltest_link1_add_clause_i(cond, function, json_integer(arg));
2229 } else {
2230 ovs_fatal(0, "Unsupported columns name %s", column);
2231 }
2232 }
2233
2234 static void
2235 parse_link2_json_clause(struct ovsdb_idl_condition *cond,
2236 enum ovsdb_function function,
2237 const char *column, const struct json *arg)
2238 {
2239 if (!strcmp(column, "i")) {
2240 idltest_link2_add_clause_i(cond, function, json_integer(arg));
2241 } else {
2242 ovs_fatal(0, "Unsupported columns name %s", column);
2243 }
2244 }
2245
2246 static void
2247 update_conditions(struct ovsdb_idl *idl, char *commands)
2248 {
2249 char *cmd, *save_ptr1 = NULL;
2250 const struct ovsdb_idl_table_class *tc;
2251
2252 for (cmd = strtok_r(commands, ";", &save_ptr1); cmd;
2253 cmd = strtok_r(NULL, ";", &save_ptr1)) {
2254 char *save_ptr2 = NULL;
2255 char *table_name = strtok_r(cmd, " ", &save_ptr2);
2256 struct json *json = parse_json(save_ptr2);
2257 int i;
2258
2259 if (json->type != JSON_ARRAY) {
2260 ovs_fatal(0, "condition should be an array");
2261 }
2262
2263 tc = find_table_class(table_name);
2264 if (!tc) {
2265 ovs_fatal(0, "Table %s does not exist", table_name);
2266 }
2267
2268 struct ovsdb_idl_condition cond = OVSDB_IDL_CONDITION_INIT(&cond);
2269 for (i = 0; i < json->u.array.n; i++) {
2270 const struct json *clause = json->u.array.elems[i];
2271 if (clause->type == JSON_TRUE) {
2272 ovsdb_idl_condition_add_clause_true(&cond);
2273 } else if (clause->type != JSON_ARRAY || clause->u.array.n != 3
2274 || clause->u.array.elems[0]->type != JSON_STRING
2275 || clause->u.array.elems[1]->type != JSON_STRING) {
2276 ovs_fatal(0, "Error parsing condition");
2277 } else {
2278 enum ovsdb_function function;
2279 const char *function_s = json_string(clause->u.array.elems[1]);
2280 struct ovsdb_error *error = ovsdb_function_from_string(
2281 function_s, &function);
2282 if (error) {
2283 ovs_fatal(0, "unknown clause function %s", function_s);
2284 }
2285
2286 const char *column = json_string(clause->u.array.elems[0]);
2287 const struct json *arg = clause->u.array.elems[2];
2288 if (!strcmp(table_name, "simple")) {
2289 parse_simple_json_clause(&cond, function, column, arg);
2290 } else if (!strcmp(table_name, "link1")) {
2291 parse_link1_json_clause(&cond, function, column, arg);
2292 } else if (!strcmp(table_name, "link2")) {
2293 parse_link2_json_clause(&cond, function, column, arg);
2294 }
2295 }
2296 }
2297
2298 unsigned int seqno = ovsdb_idl_get_condition_seqno(idl);
2299 unsigned int next_seqno = ovsdb_idl_set_condition(idl, tc, &cond);
2300 if (seqno == next_seqno ) {
2301 ovs_fatal(0, "condition unchanged");
2302 }
2303 ovsdb_idl_condition_destroy(&cond);
2304 json_destroy(json);
2305 }
2306 }
2307
2308 static void
2309 do_idl(struct ovs_cmdl_context *ctx)
2310 {
2311 struct jsonrpc *rpc;
2312 struct ovsdb_idl *idl;
2313 unsigned int seqno = 0;
2314 struct ovsdb_symbol_table *symtab;
2315 size_t n_uuids = 0;
2316 int step = 0;
2317 int error;
2318 int i;
2319 bool track;
2320
2321 track = ((struct test_ovsdb_pvt_context *)(ctx->pvt))->track;
2322
2323 idl = ovsdb_idl_create(ctx->argv[1], &idltest_idl_class, true, true);
2324 if (ctx->argc > 2) {
2325 struct stream *stream;
2326
2327 error = stream_open_block(jsonrpc_stream_open(ctx->argv[1], &stream,
2328 DSCP_DEFAULT), &stream);
2329 if (error) {
2330 ovs_fatal(error, "failed to connect to \"%s\"", ctx->argv[1]);
2331 }
2332 rpc = jsonrpc_open(stream);
2333 } else {
2334 rpc = NULL;
2335 }
2336
2337 if (track) {
2338 ovsdb_idl_track_add_all(idl);
2339 }
2340
2341 setvbuf(stdout, NULL, _IONBF, 0);
2342
2343 symtab = ovsdb_symbol_table_create();
2344 const char cond_s[] = "condition ";
2345 if (ctx->argc > 2 && strstr(ctx->argv[2], cond_s)) {
2346 update_conditions(idl, ctx->argv[2] + strlen(cond_s));
2347 printf("%03d: change conditions\n", step++);
2348 i = 3;
2349 } else {
2350 i = 2;
2351 }
2352 for (; i < ctx->argc; i++) {
2353 char *arg = ctx->argv[i];
2354 struct jsonrpc_msg *request, *reply;
2355
2356 if (*arg == '+') {
2357 /* The previous transaction didn't change anything. */
2358 arg++;
2359 } else {
2360 /* Wait for update. */
2361 for (;;) {
2362 ovsdb_idl_run(idl);
2363 ovsdb_idl_check_consistency(idl);
2364 if (ovsdb_idl_get_seqno(idl) != seqno) {
2365 break;
2366 }
2367 jsonrpc_run(rpc);
2368
2369 ovsdb_idl_wait(idl);
2370 jsonrpc_wait(rpc);
2371 poll_block();
2372 }
2373
2374 /* Print update. */
2375 if (track) {
2376 print_idl_track(idl, step++, ovsdb_idl_get_seqno(idl));
2377 ovsdb_idl_track_clear(idl);
2378 } else {
2379 print_idl(idl, step++);
2380 }
2381 }
2382 seqno = ovsdb_idl_get_seqno(idl);
2383
2384 if (!strcmp(arg, "reconnect")) {
2385 printf("%03d: reconnect\n", step++);
2386 ovsdb_idl_force_reconnect(idl);
2387 } else if (!strncmp(arg, cond_s, strlen(cond_s))) {
2388 update_conditions(idl, arg + strlen(cond_s));
2389 printf("%03d: change conditions\n", step++);
2390 } else if (arg[0] != '[') {
2391 idl_set(idl, arg, step++);
2392 } else {
2393 struct json *json = parse_json(arg);
2394 substitute_uuids(json, symtab);
2395 request = jsonrpc_create_request("transact", json, NULL);
2396 error = jsonrpc_transact_block(rpc, request, &reply);
2397 if (error || reply->error) {
2398 ovs_fatal(error, "jsonrpc transaction failed");
2399 }
2400 printf("%03d: ", step++);
2401 if (reply->result) {
2402 parse_uuids(reply->result, symtab, &n_uuids);
2403 }
2404 json_destroy(reply->id);
2405 reply->id = NULL;
2406 print_and_free_json(jsonrpc_msg_to_json(reply));
2407 }
2408 }
2409 ovsdb_symbol_table_destroy(symtab);
2410
2411 if (rpc) {
2412 jsonrpc_close(rpc);
2413 }
2414 for (;;) {
2415 ovsdb_idl_run(idl);
2416 ovsdb_idl_check_consistency(idl);
2417 if (ovsdb_idl_get_seqno(idl) != seqno) {
2418 break;
2419 }
2420 ovsdb_idl_wait(idl);
2421 poll_block();
2422 }
2423 print_idl(idl, step++);
2424 ovsdb_idl_track_clear(idl);
2425 ovsdb_idl_destroy(idl);
2426 printf("%03d: done\n", step);
2427 }
2428
2429 static void
2430 print_idl_row_simple2(const struct idltest_simple2 *s, int step)
2431 {
2432 size_t i;
2433 const struct ovsdb_datum *smap, *imap;
2434
2435 smap = idltest_simple2_get_smap(s, OVSDB_TYPE_STRING, OVSDB_TYPE_STRING);
2436 imap = idltest_simple2_get_imap(s, OVSDB_TYPE_INTEGER, OVSDB_TYPE_STRING);
2437 printf("%03d: name=%s smap=[",
2438 step, s->name);
2439 for (i = 0; i < smap->n; i++) {
2440 printf("[%s : %s]%s", smap->keys[i].string, smap->values[i].string,
2441 i < smap->n-1? ",": "");
2442 }
2443 printf("] imap=[");
2444 for (i = 0; i < imap->n; i++) {
2445 printf("[%"PRId64" : %s]%s", imap->keys[i].integer, imap->values[i].string,
2446 i < imap->n-1? ",":"");
2447 }
2448 printf("]\n");
2449 }
2450
2451 static void
2452 dump_simple2(struct ovsdb_idl *idl,
2453 const struct idltest_simple2 *myRow,
2454 int step)
2455 {
2456 IDLTEST_SIMPLE2_FOR_EACH(myRow, idl) {
2457 print_idl_row_simple2(myRow, step);
2458 }
2459 }
2460
2461 static void
2462 do_idl_partial_update_map_column(struct ovs_cmdl_context *ctx)
2463 {
2464 struct ovsdb_idl *idl;
2465 struct ovsdb_idl_txn *myTxn;
2466 const struct idltest_simple2 *myRow;
2467 const struct ovsdb_datum *smap, *imap OVS_UNUSED;
2468 int step = 0;
2469 char key_to_delete[100];
2470
2471 idl = ovsdb_idl_create(ctx->argv[1], &idltest_idl_class, false, true);
2472 ovsdb_idl_add_table(idl, &idltest_table_simple2);
2473 ovsdb_idl_add_column(idl, &idltest_simple2_col_name);
2474 ovsdb_idl_add_column(idl, &idltest_simple2_col_smap);
2475 ovsdb_idl_add_column(idl, &idltest_simple2_col_imap);
2476 ovsdb_idl_get_initial_snapshot(idl);
2477 setvbuf(stdout, NULL, _IONBF, 0);
2478 ovsdb_idl_run(idl);
2479
2480 /* Display original data in table. */
2481 myRow = NULL;
2482 printf("%03d: Getting records\n", step++);
2483 dump_simple2(idl, myRow, step++);
2484
2485 /* Insert new elements in different map columns. */
2486 myRow = idltest_simple2_first(idl);
2487 myTxn = ovsdb_idl_txn_create(idl);
2488 idltest_simple2_get_smap(myRow, OVSDB_TYPE_STRING,
2489 OVSDB_TYPE_STRING);
2490 idltest_simple2_update_smap_setkey(myRow, "key1", "myList1");
2491 imap = idltest_simple2_get_imap(myRow, OVSDB_TYPE_INTEGER,
2492 OVSDB_TYPE_STRING);
2493 idltest_simple2_update_imap_setkey(myRow, 3, "myids2");
2494 idltest_simple2_set_name(myRow, "String2");
2495 ovsdb_idl_txn_commit_block(myTxn);
2496 ovsdb_idl_txn_destroy(myTxn);
2497 ovsdb_idl_get_initial_snapshot(idl);
2498 printf("%03d: After insert element\n", step++);
2499 dump_simple2(idl, myRow, step++);
2500
2501 /* Insert duplicate element. */
2502 myTxn = ovsdb_idl_txn_create(idl);
2503 idltest_simple2_update_smap_setkey(myRow, "key1", "myList1");
2504 ovsdb_idl_txn_commit_block(myTxn);
2505 ovsdb_idl_txn_destroy(myTxn);
2506 ovsdb_idl_get_initial_snapshot(idl);
2507 printf("%03d: After insert duplicated element\n", step++);
2508 dump_simple2(idl, myRow, step++);
2509
2510 /* Deletes an element of a map column. */
2511 myRow = idltest_simple2_first(idl);
2512 myTxn = ovsdb_idl_txn_create(idl);
2513 smap = idltest_simple2_get_smap(myRow, OVSDB_TYPE_STRING,
2514 OVSDB_TYPE_STRING);
2515 strcpy(key_to_delete, smap->keys[0].string);
2516 idltest_simple2_update_smap_delkey(myRow, smap->keys[0].string);
2517 ovsdb_idl_txn_commit_block(myTxn);
2518 ovsdb_idl_txn_destroy(myTxn);
2519 ovsdb_idl_get_initial_snapshot(idl);
2520 printf("%03d: After delete element\n", step++);
2521 dump_simple2(idl, myRow, step++);
2522
2523 /* Try to delete a deleted element of a map column. */
2524 myTxn = ovsdb_idl_txn_create(idl);
2525 idltest_simple2_update_smap_delkey(myRow, key_to_delete);
2526 ovsdb_idl_txn_commit_block(myTxn);
2527 ovsdb_idl_txn_destroy(myTxn);
2528 ovsdb_idl_get_initial_snapshot(idl);
2529 printf("%03d: After trying to delete a deleted element\n", step++);
2530 dump_simple2(idl, myRow, step++);
2531
2532 printf("%03d: End test\n", step);
2533 return;
2534 }
2535
2536 static void
2537 print_idl_row_simple3(const struct idltest_simple3 *s, int step)
2538 {
2539 size_t i;
2540 const struct ovsdb_datum *uset;
2541 const struct ovsdb_datum *uref;
2542
2543 uset = idltest_simple3_get_uset(s, OVSDB_TYPE_UUID);
2544 printf("%03d: name=%s uset=[",
2545 step, s->name);
2546 for (i = 0; i < uset->n; i++) {
2547 printf("["UUID_FMT"]%s", UUID_ARGS(&(uset->keys[i].uuid)), i < uset->n-1? ",": "");
2548 }
2549 uref = idltest_simple3_get_uref(s, OVSDB_TYPE_UUID);
2550 printf("] uref=[");
2551 for (i = 0; i < uref->n; i++) {
2552 printf("["UUID_FMT"]%s", UUID_ARGS(&(uref->keys[i].uuid)), i < uref->n-1? ",": "");
2553 }
2554 printf("]\n");
2555 }
2556
2557 static void
2558 dump_simple3(struct ovsdb_idl *idl,
2559 const struct idltest_simple3 *myRow,
2560 int step)
2561 {
2562 IDLTEST_SIMPLE3_FOR_EACH(myRow, idl) {
2563 print_idl_row_simple3(myRow, step);
2564 }
2565 }
2566
2567 static void
2568 do_idl_partial_update_set_column(struct ovs_cmdl_context *ctx)
2569 {
2570 struct ovsdb_idl *idl;
2571 struct ovsdb_idl_txn *myTxn;
2572 const struct idltest_simple3 *myRow;
2573 struct idltest_simple4 *myRow2;
2574 const struct ovsdb_datum *uset OVS_UNUSED;
2575 const struct ovsdb_datum *uref OVS_UNUSED;
2576 int step = 0;
2577
2578 idl = ovsdb_idl_create(ctx->argv[1], &idltest_idl_class, false, true);
2579 ovsdb_idl_add_table(idl, &idltest_table_simple3);
2580 ovsdb_idl_add_column(idl, &idltest_simple3_col_name);
2581 ovsdb_idl_add_column(idl, &idltest_simple3_col_uset);
2582 ovsdb_idl_add_column(idl, &idltest_simple3_col_uref);
2583 ovsdb_idl_add_table(idl, &idltest_table_simple4);
2584 ovsdb_idl_add_column(idl, &idltest_simple4_col_name);
2585 ovsdb_idl_get_initial_snapshot(idl);
2586 setvbuf(stdout, NULL, _IONBF, 0);
2587 ovsdb_idl_run(idl);
2588
2589 /* Display original data in table. */
2590 myRow = NULL;
2591 printf("%03d: Getting records\n", step++);
2592 dump_simple3(idl, myRow, step++);
2593
2594 /* Insert new elements in different map columns. */
2595 myRow = idltest_simple3_first(idl);
2596 myTxn = ovsdb_idl_txn_create(idl);
2597 idltest_simple3_get_uset(myRow, OVSDB_TYPE_UUID);
2598 struct uuid uuid_to_add;
2599 uuid_from_string(&uuid_to_add, "001e43d2-dd3f-4616-ab6a-83a490bb0991");
2600 idltest_simple3_update_uset_addvalue(myRow, uuid_to_add);
2601 idltest_simple3_set_name(myRow, "String2");
2602 ovsdb_idl_txn_commit_block(myTxn);
2603 ovsdb_idl_txn_destroy(myTxn);
2604 ovsdb_idl_get_initial_snapshot(idl);
2605 printf("%03d: After rename+add new value\n", step++);
2606 dump_simple3(idl, myRow, step++);
2607
2608 /* Insert duplicate element. */
2609 myTxn = ovsdb_idl_txn_create(idl);
2610 struct uuid uuid_to_add2;
2611 uuid_from_string(&uuid_to_add2, "0026b3ba-571b-4729-8227-d860a5210ab8");
2612 idltest_simple3_update_uset_addvalue(myRow, uuid_to_add2);
2613 ovsdb_idl_txn_commit_block(myTxn);
2614 ovsdb_idl_txn_destroy(myTxn);
2615 ovsdb_idl_get_initial_snapshot(idl);
2616 printf("%03d: After add new value\n", step++);
2617 dump_simple3(idl, myRow, step++);
2618
2619 /* Deletes an element of a set column. */
2620 myRow = idltest_simple3_first(idl);
2621 myTxn = ovsdb_idl_txn_create(idl);
2622 uset = idltest_simple3_get_uset(myRow, OVSDB_TYPE_UUID);
2623 idltest_simple3_update_uset_delvalue(myRow, uuid_to_add);
2624 ovsdb_idl_txn_commit_block(myTxn);
2625 ovsdb_idl_txn_destroy(myTxn);
2626 ovsdb_idl_get_initial_snapshot(idl);
2627 printf("%03d: After delete value\n", step++);
2628 dump_simple3(idl, myRow, step++);
2629
2630 /* Try to delete a deleted element of a map column. */
2631 myRow = idltest_simple3_first(idl);
2632 myTxn = ovsdb_idl_txn_create(idl);
2633 idltest_simple3_update_uset_delvalue(myRow, uuid_to_add);
2634 ovsdb_idl_txn_commit_block(myTxn);
2635 ovsdb_idl_txn_destroy(myTxn);
2636 ovsdb_idl_get_initial_snapshot(idl);
2637 printf("%03d: After trying to delete a deleted value\n", step++);
2638 dump_simple3(idl, myRow, step++);
2639
2640 /* Adds to a table and update a strong reference in another table. */
2641 myRow = idltest_simple3_first(idl);
2642 myTxn = ovsdb_idl_txn_create(idl);
2643 myRow2 = idltest_simple4_insert(myTxn);
2644 idltest_simple4_set_name(myRow2, "test");
2645 idltest_simple3_update_uref_addvalue(myRow, myRow2);
2646 ovsdb_idl_txn_commit_block(myTxn);
2647 ovsdb_idl_txn_destroy(myTxn);
2648 ovsdb_idl_get_initial_snapshot(idl);
2649 printf("%03d: After add to other table + set of strong ref\n", step++);
2650 dump_simple3(idl, myRow, step++);
2651 printf("%03d: End test\n", step);
2652 return;
2653 }
2654
2655 static struct ovs_cmdl_command all_commands[] = {
2656 { "log-io", NULL, 2, INT_MAX, do_log_io, OVS_RO },
2657 { "default-atoms", NULL, 0, 0, do_default_atoms, OVS_RO },
2658 { "default-data", NULL, 0, 0, do_default_data, OVS_RO },
2659 { "diff-data", NULL, 3, INT_MAX, do_diff_data, OVS_RO },
2660 { "parse-atomic-type", NULL, 1, 1, do_parse_atomic_type, OVS_RO },
2661 { "parse-base-type", NULL, 1, 1, do_parse_base_type, OVS_RO },
2662 { "parse-type", NULL, 1, 1, do_parse_type, OVS_RO },
2663 { "parse-atoms", NULL, 2, INT_MAX, do_parse_atoms, OVS_RO },
2664 { "parse-atom-strings", NULL, 2, INT_MAX, do_parse_atom_strings, OVS_RO },
2665 { "parse-data", NULL, 2, INT_MAX, do_parse_data, OVS_RO },
2666 { "parse-data-strings", NULL, 2, INT_MAX, do_parse_data_strings, OVS_RO },
2667 { "sort-atoms", NULL, 2, 2, do_sort_atoms, OVS_RO },
2668 { "parse-column", NULL, 2, 2, do_parse_column, OVS_RO },
2669 { "parse-table", NULL, 2, 3, do_parse_table, OVS_RO },
2670 { "parse-rows", NULL, 2, INT_MAX, do_parse_rows, OVS_RO },
2671 { "compare-rows", NULL, 2, INT_MAX, do_compare_rows, OVS_RO },
2672 { "parse-conditions", NULL, 2, INT_MAX, do_parse_conditions, OVS_RO },
2673 { "evaluate-conditions", NULL, 3, 3, do_evaluate_conditions, OVS_RO },
2674 { "evaluate-conditions-any", NULL, 3, 3, do_evaluate_conditions_any, OVS_RO },
2675 { "compare-conditions", NULL, 2, 2, do_compare_conditions, OVS_RO },
2676 { "parse-mutations", NULL, 2, INT_MAX, do_parse_mutations, OVS_RO },
2677 { "execute-mutations", NULL, 3, 3, do_execute_mutations, OVS_RO },
2678 { "query", NULL, 3, 3, do_query, OVS_RO },
2679 { "query-distinct", NULL, 4, 4, do_query_distinct, OVS_RO },
2680 { "transact", NULL, 1, INT_MAX, do_transact, OVS_RO },
2681 { "parse-schema", NULL, 1, 1, do_parse_schema, OVS_RO },
2682 { "execute", NULL, 2, INT_MAX, do_execute, OVS_RO },
2683 { "execute-readonly", NULL, 2, INT_MAX, do_execute_ro, OVS_RO },
2684 { "trigger", NULL, 2, INT_MAX, do_trigger, OVS_RO },
2685 { "idl", NULL, 1, INT_MAX, do_idl, OVS_RO },
2686 { "idl-partial-update-map-column", NULL, 1, INT_MAX,
2687 do_idl_partial_update_map_column, OVS_RO },
2688 { "idl-partial-update-set-column", NULL, 1, INT_MAX,
2689 do_idl_partial_update_set_column, OVS_RO },
2690 { "help", NULL, 0, INT_MAX, do_help, OVS_RO },
2691 { NULL, NULL, 0, 0, NULL, OVS_RO },
2692 };
2693
2694 static struct ovs_cmdl_command *
2695 get_all_commands(void)
2696 {
2697 return all_commands;
2698 }