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