+/* Returns JSON for a <row-update2> (as described in ovsdb-server(1) mapage)
+ * for 'row' within * 'mt', or NULL if no row update should be sent.
+ *
+ * The caller should specify 'initial' as true if the returned JSON is
+ * going to be used as part of the initial reply to a "monitor2" request,
+ * false if it is going to be used as part of an "update2" notification.
+ *
+ * 'changed' must be a scratch buffer for internal use that is at least
+ * bitmap_n_bytes(mt->n_columns) bytes long. */
+static struct json *
+ovsdb_monitor_compose_row_update2(
+ const struct ovsdb_monitor_table *mt,
+ const struct ovsdb_monitor_row *row,
+ bool initial, unsigned long int *changed)
+{
+ enum ovsdb_monitor_selection type;
+ struct json *row_update2, *diff_json;
+ size_t i;
+
+ type = ovsdb_monitor_row_update_type(initial, row->old, row->new);
+ if (ovsdb_monitor_row_skip_update(mt, row, type, changed)) {
+ return NULL;
+ }
+
+ row_update2 = json_object_create();
+ if (type == OJMS_DELETE) {
+ json_object_put(row_update2, "delete", json_null_create());
+ } else {
+ diff_json = json_object_create();
+ const char *op;
+
+ for (i = 0; i < mt->n_columns; i++) {
+ const struct ovsdb_monitor_column *c = &mt->columns[i];
+
+ if (!(type & c->select)) {
+ /* We don't care about this type of change for this
+ * particular column (but we will care about it for some
+ * other column). */
+ continue;
+ }
+
+ if (type == OJMS_MODIFY) {
+ struct ovsdb_datum diff;
+
+ if (!bitmap_is_set(changed, i)) {
+ continue;
+ }
+
+ ovsdb_datum_diff(&diff ,&row->old[i], &row->new[i],
+ &c->column->type);
+ json_object_put(diff_json, c->column->name,
+ ovsdb_datum_to_json(&diff, &c->column->type));
+ ovsdb_datum_destroy(&diff, &c->column->type);
+ } else {
+ if (!ovsdb_datum_is_default(&row->new[i], &c->column->type)) {
+ json_object_put(diff_json, c->column->name,
+ ovsdb_datum_to_json(&row->new[i],
+ &c->column->type));
+ }
+ }
+ }
+
+ op = type == OJMS_INITIAL ? "initial"
+ : type == OJMS_MODIFY ? "modify" : "insert";
+ json_object_put(row_update2, op, diff_json);
+ }
+
+ return row_update2;
+}
+