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