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