/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdlib.h>
#include "command-line.h"
+#include "dynamic-string.h"
#include "json.h"
#include "jsonrpc.h"
#include "ovsdb-data.h"
#include "ovsdb/condition.h"
#include "ovsdb/file.h"
#include "ovsdb/log.h"
+#include "ovsdb/mutation.h"
#include "ovsdb/ovsdb.h"
#include "ovsdb/query.h"
#include "ovsdb/row.h"
" open FILE with FLAGS, run COMMANDs\n"
" parse-atomic-type TYPE\n"
" parse TYPE as OVSDB atomic type, and re-serialize\n"
+ " parse-base-type TYPE\n"
+ " parse TYPE as OVSDB base type, and re-serialize\n"
" parse-type JSON\n"
" parse JSON as OVSDB type, and re-serialize\n"
" parse-atoms TYPE ATOM...\n"
- " parse ATOMs as atoms of given TYPE, and re-serialize\n"
+ " parse JSON ATOMs as atoms of TYPE, and re-serialize\n"
+ " parse-atom-strings TYPE ATOM...\n"
+ " parse string ATOMs as atoms of given TYPE, and re-serialize\n"
" sort-atoms TYPE ATOM...\n"
- " print ATOMs in sorted order, and re-serialize\n"
+ " print JSON ATOMs in sorted order\n"
" parse-data TYPE DATUM...\n"
- " parse DATUMs as data of given TYPE, and re-serialize\n"
+ " parse JSON DATUMs as data of given TYPE, and re-serialize\n"
+ " parse-data-strings TYPE DATUM...\n"
+ " parse string DATUMs as data of given TYPE, and re-serialize\n"
" parse-column NAME OBJECT\n"
" parse column NAME with info OBJECT, and re-serialize\n"
" parse-table NAME OBJECT\n"
" parse each CONDITION on TABLE, and re-serialize\n"
" evaluate-conditions TABLE [CONDITION,...] [ROW,...]\n"
" test CONDITIONS on TABLE against each ROW, print results\n"
+ " parse-mutations TABLE MUTATION...\n"
+ " parse each MUTATION on TABLE, and re-serialize\n"
+ " execute-mutations TABLE [MUTATION,...] [ROW,...]\n"
+ " execute MUTATIONS on TABLE on each ROW, print results\n"
" query TABLE [ROW,...] [CONDITION,...]\n"
" add each ROW to TABLE, then query and print the rows that\n"
" satisfy each CONDITION.\n"
" query-distinct TABLE [ROW,...] [CONDITION,...] COLUMNS\n"
" add each ROW to TABLE, then query and print the rows that\n"
" satisfy each CONDITION and have distinct COLUMNS.\n"
+ " parse-schema JSON\n"
+ " parse JSON as an OVSDB schema, and re-serialize\n"
" transact COMMAND\n"
" execute each specified transactional COMMAND:\n"
" commit\n"
free(string);
}
+static void
+print_and_free_ovsdb_error(struct ovsdb_error *error)
+{
+ char *string = ovsdb_error_to_string(error);
+ ovsdb_error_destroy(error);
+ puts(string);
+ free(string);
+}
+
static void
check_ovsdb_error(struct ovsdb_error *error)
{
if (error) {
- ovs_fatal(0, "%s", ovsdb_error_to_string(error));
+ char *s = ovsdb_error_to_string(error);
+ ovsdb_error_destroy(error);
+ ovs_fatal(0, "%s", s);
+ }
+}
+
+static void
+die_if_error(char *error)
+{
+ if (error) {
+ ovs_fatal(0, "%s", error);
}
}
\f
do_log_io(int argc, char *argv[])
{
const char *name = argv[1];
- char *mode = argv[2];
+ char *mode_string = argv[2];
struct ovsdb_error *error;
+ enum ovsdb_log_open_mode mode;
struct ovsdb_log *log;
- char *save_ptr = NULL;
- const char *token;
- int flags;
int i;
- for (flags = 0, token = strtok_r(mode, " |", &save_ptr); token != NULL;
- token = strtok_r(NULL, " |", &save_ptr))
- {
- if (!strcmp(token, "O_RDONLY")) {
- flags |= O_RDONLY;
- } else if (!strcmp(token, "O_RDWR")) {
- flags |= O_RDWR;
- } else if (!strcmp(token, "O_TRUNC")) {
- flags |= O_TRUNC;
- } else if (!strcmp(token, "O_CREAT")) {
- flags |= O_CREAT;
- } else if (!strcmp(token, "O_EXCL")) {
- flags |= O_EXCL;
- } else if (!strcmp(token, "O_TRUNC")) {
- flags |= O_TRUNC;
- }
+ if (!strcmp(mode_string, "read-only")) {
+ mode = OVSDB_LOG_READ_ONLY;
+ } else if (!strcmp(mode_string, "read/write")) {
+ mode = OVSDB_LOG_READ_WRITE;
+ } else if (!strcmp(mode_string, "create")) {
+ mode = OVSDB_LOG_CREATE;
+ } else {
+ ovs_fatal(0, "unknown log-io open mode \"%s\"", mode_string);
}
- check_ovsdb_error(ovsdb_log_open(name, flags, &log));
+ check_ovsdb_error(ovsdb_log_open(name, mode, -1, &log));
printf("%s: open successful\n", name);
for (i = 3; i < argc; i++) {
char *s = ovsdb_error_to_string(error);
printf("%s: %s failed: %s\n", name, command, s);
free(s);
+ ovsdb_error_destroy(error);
} else {
printf("%s: %s successful\n", name, command);
}
}
static void
-do_parse_atomic_type(int argc UNUSED, char *argv[])
+do_parse_atomic_type(int argc OVS_UNUSED, char *argv[])
{
enum ovsdb_atomic_type type;
struct json *json;
}
static void
-do_parse_type(int argc UNUSED, char *argv[])
+do_parse_base_type(int argc OVS_UNUSED, char *argv[])
+{
+ struct ovsdb_base_type base;
+ struct json *json;
+
+ json = unbox_json(parse_json(argv[1]));
+ check_ovsdb_error(ovsdb_base_type_from_json(&base, json));
+ json_destroy(json);
+ print_and_free_json(ovsdb_base_type_to_json(&base));
+ ovsdb_base_type_destroy(&base);
+}
+
+static void
+do_parse_type(int argc OVS_UNUSED, char *argv[])
{
struct ovsdb_type type;
struct json *json;
check_ovsdb_error(ovsdb_type_from_json(&type, json));
json_destroy(json);
print_and_free_json(ovsdb_type_to_json(&type));
+ ovsdb_type_destroy(&type);
}
static void
do_parse_atoms(int argc, char *argv[])
{
- enum ovsdb_atomic_type type;
+ struct ovsdb_base_type base;
struct json *json;
int i;
json = unbox_json(parse_json(argv[1]));
- check_ovsdb_error(ovsdb_atomic_type_from_json(&type, json));
+ check_ovsdb_error(ovsdb_base_type_from_json(&base, json));
json_destroy(json);
for (i = 2; i < argc; i++) {
+ struct ovsdb_error *error;
union ovsdb_atom atom;
json = unbox_json(parse_json(argv[i]));
- check_ovsdb_error(ovsdb_atom_from_json(&atom, type, json, NULL));
+ error = ovsdb_atom_from_json(&atom, &base, json, NULL);
json_destroy(json);
- print_and_free_json(ovsdb_atom_to_json(&atom, type));
+ if (error) {
+ print_and_free_ovsdb_error(error);
+ } else {
+ print_and_free_json(ovsdb_atom_to_json(&atom, base.type));
+ ovsdb_atom_destroy(&atom, base.type);
+ }
+ }
+ ovsdb_base_type_destroy(&base);
+}
- ovsdb_atom_destroy(&atom, type);
+static void
+do_parse_atom_strings(int argc, char *argv[])
+{
+ struct ovsdb_base_type base;
+ struct json *json;
+ int i;
+
+ json = unbox_json(parse_json(argv[1]));
+ check_ovsdb_error(ovsdb_base_type_from_json(&base, json));
+ json_destroy(json);
+
+ for (i = 2; i < argc; i++) {
+ union ovsdb_atom atom;
+ struct ds out;
+
+ die_if_error(ovsdb_atom_from_string(&atom, &base, argv[i]));
+
+ ds_init(&out);
+ ovsdb_atom_to_string(&atom, base.type, &out);
+ puts(ds_cstr(&out));
+ ds_destroy(&out);
+
+ ovsdb_atom_destroy(&atom, base.type);
}
+ ovsdb_base_type_destroy(&base);
}
static void
ovsdb_datum_destroy(&datum, &type);
}
+ ovsdb_type_destroy(&type);
+}
+
+static void
+do_parse_data_strings(int argc, char *argv[])
+{
+ struct ovsdb_type type;
+ struct json *json;
+ int i;
+
+ json = unbox_json(parse_json(argv[1]));
+ check_ovsdb_error(ovsdb_type_from_json(&type, json));
+ json_destroy(json);
+
+ for (i = 2; i < argc; i++) {
+ struct ovsdb_datum datum;
+ struct ds out;
+
+ die_if_error(ovsdb_datum_from_string(&datum, &type, argv[i]));
+
+ ds_init(&out);
+ ovsdb_datum_to_string(&datum, &type, &out);
+ puts(ds_cstr(&out));
+ ds_destroy(&out);
+
+ ovsdb_datum_destroy(&datum, &type);
+ }
+ ovsdb_type_destroy(&type);
}
static enum ovsdb_atomic_type compare_atoms_atomic_type;
}
static void
-do_sort_atoms(int argc UNUSED, char *argv[])
+do_sort_atoms(int argc OVS_UNUSED, char *argv[])
{
- enum ovsdb_atomic_type type;
+ struct ovsdb_base_type base;
union ovsdb_atom *atoms;
struct json *json, **json_atoms;
size_t n_atoms;
int i;
json = unbox_json(parse_json(argv[1]));
- check_ovsdb_error(ovsdb_atomic_type_from_json(&type, json));
+ check_ovsdb_error(ovsdb_base_type_from_json(&base, json));
json_destroy(json);
json = unbox_json(parse_json(argv[2]));
n_atoms = json->u.array.n;
atoms = xmalloc(n_atoms * sizeof *atoms);
for (i = 0; i < n_atoms; i++) {
- check_ovsdb_error(ovsdb_atom_from_json(&atoms[i], type,
+ check_ovsdb_error(ovsdb_atom_from_json(&atoms[i], &base,
json->u.array.elems[i], NULL));
}
json_destroy(json);
/* Sort atoms. */
- compare_atoms_atomic_type = type;
+ compare_atoms_atomic_type = base.type;
qsort(atoms, n_atoms, sizeof *atoms, compare_atoms);
/* Convert internal representation back to JSON. */
json_atoms = xmalloc(n_atoms * sizeof *json_atoms);
for (i = 0; i < n_atoms; i++) {
- json_atoms[i] = ovsdb_atom_to_json(&atoms[i], type);
- ovsdb_atom_destroy(&atoms[i], type);
+ json_atoms[i] = ovsdb_atom_to_json(&atoms[i], base.type);
+ ovsdb_atom_destroy(&atoms[i], base.type);
}
print_and_free_json(json_array_create(json_atoms, n_atoms));
+ free(atoms);
+ ovsdb_base_type_destroy(&base);
}
static void
-do_parse_column(int argc UNUSED, char *argv[])
+do_parse_column(int argc OVS_UNUSED, char *argv[])
{
struct ovsdb_column *column;
struct json *json;
}
static void
-do_parse_table(int argc UNUSED, char *argv[])
+do_parse_table(int argc OVS_UNUSED, char *argv[])
{
struct ovsdb_table_schema *ts;
struct json *json;
}
}
}
+ for (i = 0; i < n_rows; i++) {
+ ovsdb_row_destroy(rows[i]);
+ free(names[i]);
+ }
free(rows);
free(names);
}
static void
-do_evaluate_conditions(int argc UNUSED, char *argv[])
+do_evaluate_conditions(int argc OVS_UNUSED, char *argv[])
{
struct ovsdb_table_schema *ts;
struct ovsdb_table *table;
for (i = 0; i < n_conditions; i++) {
ovsdb_condition_destroy(&conditions[i]);
}
+ free(conditions);
for (i = 0; i < n_rows; i++) {
ovsdb_row_destroy(rows[i]);
}
+ free(rows);
+ ovsdb_table_destroy(table); /* Also destroys 'ts'. */
+}
+
+static void
+do_parse_mutations(int argc, char *argv[])
+{
+ struct ovsdb_table_schema *ts;
+ struct json *json;
+ int exit_code = 0;
+ int i;
+
+ json = unbox_json(parse_json(argv[1]));
+ check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
+ json_destroy(json);
+
+ for (i = 2; i < argc; i++) {
+ struct ovsdb_mutation_set set;
+ struct ovsdb_error *error;
+
+ json = parse_json(argv[i]);
+ error = ovsdb_mutation_set_from_json(ts, json, NULL, &set);
+ if (!error) {
+ print_and_free_json(ovsdb_mutation_set_to_json(&set));
+ } else {
+ char *s = ovsdb_error_to_string(error);
+ ovs_error(0, "%s", s);
+ free(s);
+ ovsdb_error_destroy(error);
+ exit_code = 1;
+ }
+ json_destroy(json);
+
+ ovsdb_mutation_set_destroy(&set);
+ }
+ ovsdb_table_schema_destroy(ts);
+
+ exit(exit_code);
+}
+
+static void
+do_execute_mutations(int argc OVS_UNUSED, char *argv[])
+{
+ struct ovsdb_table_schema *ts;
+ struct ovsdb_table *table;
+ struct ovsdb_mutation_set *sets;
+ size_t n_sets;
+ struct ovsdb_row **rows;
+ size_t n_rows;
+ struct json *json;
+ size_t i, j;
+
+ /* Parse table schema, create table. */
+ json = unbox_json(parse_json(argv[1]));
+ check_ovsdb_error(ovsdb_table_schema_from_json(json, "mytable", &ts));
+ json_destroy(json);
+
+ table = ovsdb_table_create(ts);
+
+ /* Parse mutations. */
+ json = parse_json(argv[2]);
+ if (json->type != JSON_ARRAY) {
+ ovs_fatal(0, "MUTATION argument is not JSON array");
+ }
+ n_sets = json->u.array.n;
+ sets = xmalloc(n_sets * sizeof *sets);
+ for (i = 0; i < n_sets; i++) {
+ check_ovsdb_error(ovsdb_mutation_set_from_json(ts,
+ json->u.array.elems[i],
+ NULL, &sets[i]));
+ }
+ json_destroy(json);
+
+ /* Parse rows. */
+ json = parse_json(argv[3]);
+ if (json->type != JSON_ARRAY) {
+ ovs_fatal(0, "ROW argument is not JSON array");
+ }
+ n_rows = json->u.array.n;
+ rows = xmalloc(n_rows * sizeof *rows);
+ for (i = 0; i < n_rows; i++) {
+ rows[i] = ovsdb_row_create(table);
+ check_ovsdb_error(ovsdb_row_from_json(rows[i], json->u.array.elems[i],
+ NULL, NULL));
+ }
+ json_destroy(json);
+
+ for (i = 0; i < n_sets; i++) {
+ printf("mutation %2d:\n", i);
+ for (j = 0; j < n_rows; j++) {
+ struct ovsdb_error *error;
+ struct ovsdb_row *row;
+
+ row = ovsdb_row_clone(rows[j]);
+ error = ovsdb_mutation_set_execute(row, &sets[i]);
+
+ printf("row %zu: ", j);
+ if (error) {
+ print_and_free_ovsdb_error(error);
+ } else {
+ struct ovsdb_column_set columns;
+ struct shash_node *node;
+
+ ovsdb_column_set_init(&columns);
+ SHASH_FOR_EACH (node, &ts->columns) {
+ struct ovsdb_column *c = node->data;
+ if (!ovsdb_datum_equals(&row->fields[c->index],
+ &rows[j]->fields[c->index],
+ &c->type)) {
+ ovsdb_column_set_add(&columns, c);
+ }
+ }
+ if (columns.n_columns) {
+ print_and_free_json(ovsdb_row_to_json(row, &columns));
+ } else {
+ printf("no change\n");
+ }
+ ovsdb_column_set_destroy(&columns);
+ }
+ ovsdb_row_destroy(row);
+ }
+ printf("\n");
+ }
+
+ for (i = 0; i < n_sets; i++) {
+ ovsdb_mutation_set_destroy(&sets[i]);
+ }
+ free(sets);
+ for (i = 0; i < n_rows; i++) {
+ ovsdb_row_destroy(rows[i]);
+ }
+ free(rows);
ovsdb_table_destroy(table); /* Also destroys 'ts'. */
}
}
static void
-do_query(int argc UNUSED, char *argv[])
+do_query(int argc OVS_UNUSED, char *argv[])
{
struct do_query_cbdata cbdata;
struct ovsdb_table_schema *ts;
};
static void
-do_query_distinct(int argc UNUSED, char *argv[])
+do_query_distinct(int argc OVS_UNUSED, char *argv[])
{
struct ovsdb_column_set columns;
struct ovsdb_table_schema *ts;
/* Parse column set. */
json = parse_json(argv[4]);
- ovsdb_column_set_from_json(json, table, &columns);
+ check_ovsdb_error(ovsdb_column_set_from_json(json, table, &columns));
json_destroy(json);
/* Parse rows, add to table. */
}
static void
-do_execute(int argc UNUSED, char *argv[])
+do_parse_schema(int argc OVS_UNUSED, char *argv[])
+{
+ struct ovsdb_schema *schema;
+ struct json *json;
+
+ json = parse_json(argv[1]);
+ check_ovsdb_error(ovsdb_schema_from_json(json, &schema));
+ json_destroy(json);
+ print_and_free_json(ovsdb_schema_to_json(schema));
+ ovsdb_schema_destroy(schema);
+}
+
+static void
+do_execute(int argc OVS_UNUSED, char *argv[])
{
struct ovsdb_schema *schema;
struct json *json;
result = ovsdb_execute(db, params, 0, NULL);
s = json_to_string(result, JSSF_SORT);
printf("%s\n", s);
+ free(s);
json_destroy(params);
json_destroy(result);
}
result = ovsdb_trigger_steal_result(&t->trigger);
s = json_to_string(result, JSSF_SORT);
printf("t=%lld: trigger %d (%s): %s\n", now, t->number, title, s);
+ free(s);
json_destroy(result);
ovsdb_trigger_destroy(&t->trigger);
free(t);
}
static void
-do_trigger(int argc UNUSED, char *argv[])
+do_trigger(int argc OVS_UNUSED, char *argv[])
{
struct ovsdb_schema *schema;
struct list completions;
}
static void
-do_help(int argc UNUSED, char *argv[] UNUSED)
+do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
usage();
}
static struct ovsdb_table *do_transact_table;
static void
-do_transact_commit(int argc UNUSED, char *argv[] UNUSED)
+do_transact_commit(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
ovsdb_txn_commit(do_transact_txn, false);
do_transact_txn = NULL;
}
static void
-do_transact_abort(int argc UNUSED, char *argv[] UNUSED)
+do_transact_abort(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
ovsdb_txn_abort(do_transact_txn);
do_transact_txn = NULL;
}
static void
-do_transact_insert(int argc UNUSED, char *argv[] UNUSED)
+do_transact_insert(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
struct ovsdb_row *row;
struct uuid *uuid;
}
static void
-do_transact_delete(int argc UNUSED, char *argv[] UNUSED)
+do_transact_delete(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
const struct ovsdb_row *row = do_transact_find_row(argv[1]);
ovsdb_txn_row_delete(do_transact_txn, row);
}
static void
-do_transact_modify(int argc UNUSED, char *argv[] UNUSED)
+do_transact_modify(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
const struct ovsdb_row *row_ro;
struct ovsdb_row *row_rw;
}
static void
-do_transact_print(int argc UNUSED, char *argv[] UNUSED)
+do_transact_print(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
const struct ovsdb_row **rows;
const struct ovsdb_row *row;
char *cmd, *save_ptr1 = NULL;
struct ovsdb_idl_txn *txn;
enum ovsdb_idl_txn_status status;
+ bool increment = false;
txn = ovsdb_idl_txn_create(idl);
for (cmd = strtok_r(commands, ",", &save_ptr1); cmd;
"i=%d", atoi(arg1));
}
idltest_simple_delete(s);
+ } else if (!strcmp(name, "increment")) {
+ if (!arg2 || arg3) {
+ ovs_fatal(0, "\"set\" command requires 2 arguments");
+ }
+ ovsdb_idl_txn_increment(txn, arg1, arg2, NULL);
+ increment = true;
} else {
ovs_fatal(0, "unknown command %s", name);
}
}
- for (;;) {
- ovsdb_idl_run(idl);
- status = ovsdb_idl_txn_commit(txn);
- if (status != TXN_INCOMPLETE) {
- break;
- }
-
- ovsdb_idl_wait(idl);
- poll_block();
- }
- printf("%03d: commit, status=%s\n",
+ status = ovsdb_idl_txn_commit_block(txn);
+ printf("%03d: commit, status=%s",
step, ovsdb_idl_txn_status_to_string(status));
+ if (increment) {
+ printf(", increment=%"PRId64,
+ ovsdb_idl_txn_get_increment_new_value(txn));
+ }
+ putchar('\n');
ovsdb_idl_txn_destroy(txn);
}
int error;
int i;
+ idltest_init();
+
idl = ovsdb_idl_create(argv[1], &idltest_idl_class);
if (argc > 2) {
struct stream *stream;
- error = stream_open_block(argv[1], &stream);
+ error = stream_open_block(jsonrpc_stream_open(argv[1], &stream),
+ &stream);
if (error) {
ovs_fatal(error, "failed to connect to \"%s\"", argv[1]);
}
rpc = NULL;
}
+ setvbuf(stdout, NULL, _IOLBF, 0);
+
symtab = ovsdb_symbol_table_create();
for (i = 2; i < argc; i++) {
+ char *arg = argv[i];
struct jsonrpc_msg *request, *reply;
int error;
- seqno = print_updated_idl(idl, rpc, step++, seqno);
+ if (*arg == '+') {
+ /* The previous transaction didn't change anything. */
+ arg++;
+ } else {
+ seqno = print_updated_idl(idl, rpc, step++, seqno);
+ }
- if (!strcmp(argv[i], "reconnect")) {
+ if (!strcmp(arg, "reconnect")) {
printf("%03d: reconnect\n", step++);
ovsdb_idl_force_reconnect(idl);
- } else if (argv[i][0] != '[') {
- idl_set(idl, argv[i], step++);
+ } else if (arg[0] != '[') {
+ idl_set(idl, arg, step++);
} else {
- struct json *json = parse_json(argv[i]);
+ struct json *json = parse_json(arg);
substitute_uuids(json, symtab);
request = jsonrpc_create_request("transact", json, NULL);
error = jsonrpc_transact_block(rpc, request, &reply);
static struct command all_commands[] = {
{ "log-io", 2, INT_MAX, do_log_io },
{ "parse-atomic-type", 1, 1, do_parse_atomic_type },
+ { "parse-base-type", 1, 1, do_parse_base_type },
{ "parse-type", 1, 1, do_parse_type },
{ "parse-atoms", 2, INT_MAX, do_parse_atoms },
+ { "parse-atom-strings", 2, INT_MAX, do_parse_atom_strings },
{ "parse-data", 2, INT_MAX, do_parse_data },
+ { "parse-data-strings", 2, INT_MAX, do_parse_data_strings },
{ "sort-atoms", 2, 2, do_sort_atoms },
{ "parse-column", 2, 2, do_parse_column },
{ "parse-table", 2, 2, do_parse_table },
{ "compare-rows", 2, INT_MAX, do_compare_rows },
{ "parse-conditions", 2, INT_MAX, do_parse_conditions },
{ "evaluate-conditions", 3, 3, do_evaluate_conditions },
+ { "parse-mutations", 2, INT_MAX, do_parse_mutations },
+ { "execute-mutations", 3, 3, do_execute_mutations },
{ "query", 3, 3, do_query },
{ "query-distinct", 4, 4, do_query_distinct },
{ "transact", 1, INT_MAX, do_transact },
+ { "parse-schema", 1, 1, do_parse_schema },
{ "execute", 2, INT_MAX, do_execute },
{ "trigger", 2, INT_MAX, do_trigger },
{ "idl", 1, INT_MAX, do_idl },