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