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