+ if (schema) {
+ struct shash_node *node, *next;
+
+ SHASH_FOR_EACH_SAFE (node, next, schema) {
+ struct sset *sset = node->data;
+ sset_destroy(sset);
+ free(sset);
+ shash_delete(schema, node);
+ }
+ shash_destroy(schema);
+ free(schema);
+ }
+}
+
+/* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
+ * 7047, to obtain the names of its rows and columns. If successful, returns
+ * an shash whose keys are table names and whose values are ssets, where each
+ * sset contains the names of its table's columns. On failure (due to a parse
+ * error), returns NULL.
+ *
+ * It would also be possible to use the general-purpose OVSDB schema parser in
+ * ovsdb-server, but that's overkill, possibly too strict for the current use
+ * case, and would require restructuring ovsdb-server to separate the schema
+ * code from the rest. */
+static struct shash *
+parse_schema(const struct json *schema_json)
+{
+ struct ovsdb_parser parser;
+ const struct json *tables_json;
+ struct ovsdb_error *error;
+ struct shash_node *node;
+ struct shash *schema;
+
+ ovsdb_parser_init(&parser, schema_json, "database schema");
+ tables_json = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
+ error = ovsdb_parser_destroy(&parser);
+ if (error) {
+ log_error(error);
+ return NULL;
+ }
+
+ schema = xmalloc(sizeof *schema);
+ shash_init(schema);
+ SHASH_FOR_EACH (node, json_object(tables_json)) {
+ const char *table_name = node->name;
+ const struct json *json = node->data;
+ const struct json *columns_json;
+
+ ovsdb_parser_init(&parser, json, "table schema for table %s",
+ table_name);
+ columns_json = ovsdb_parser_member(&parser, "columns", OP_OBJECT);
+ error = ovsdb_parser_destroy(&parser);
+ if (error) {
+ log_error(error);
+ free_schema(schema);
+ return NULL;
+ }
+
+ struct sset *columns = xmalloc(sizeof *columns);
+ sset_init(columns);
+
+ struct shash_node *node2;
+ SHASH_FOR_EACH (node2, json_object(columns_json)) {
+ const char *column_name = node2->name;
+ sset_add(columns, column_name);
+ }
+ shash_add(schema, table_name, columns);
+ }
+ return schema;
+}
+
+static void
+ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl,
+ const struct json *schema_json)
+{
+ struct shash *schema = parse_schema(schema_json);