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