Clean up nicira-ext.h header a bit.
[openvswitch] / ovsdb / execution.c
index 25b34b196fcbd7528cc96edca39afe3d114b4eb5..4cb8b14c4a46193bdbe9bf6195abc8e8cfba0b33 100644 (file)
@@ -22,6 +22,7 @@
 #include "condition.h"
 #include "file.h"
 #include "json.h"
+#include "mutation.h"
 #include "ovsdb-data.h"
 #include "ovsdb-error.h"
 #include "ovsdb-parser.h"
@@ -47,14 +48,16 @@ typedef struct ovsdb_error *ovsdb_operation_executor(struct ovsdb_execution *,
                                                      struct ovsdb_parser *,
                                                      struct json *result);
 
-static struct ovsdb_error *do_commit(struct ovsdb_execution *);
 static ovsdb_operation_executor ovsdb_execute_insert;
 static ovsdb_operation_executor ovsdb_execute_select;
 static ovsdb_operation_executor ovsdb_execute_update;
+static ovsdb_operation_executor ovsdb_execute_mutate;
 static ovsdb_operation_executor ovsdb_execute_delete;
 static ovsdb_operation_executor ovsdb_execute_wait;
 static ovsdb_operation_executor ovsdb_execute_commit;
 static ovsdb_operation_executor ovsdb_execute_abort;
+static ovsdb_operation_executor ovsdb_execute_declare;
+static ovsdb_operation_executor ovsdb_execute_comment;
 
 static ovsdb_operation_executor *
 lookup_executor(const char *name)
@@ -68,10 +71,13 @@ lookup_executor(const char *name)
         { "insert", ovsdb_execute_insert },
         { "select", ovsdb_execute_select },
         { "update", ovsdb_execute_update },
+        { "mutate", ovsdb_execute_mutate },
         { "delete", ovsdb_execute_delete },
         { "wait", ovsdb_execute_wait },
         { "commit", ovsdb_execute_commit },
         { "abort", ovsdb_execute_abort },
+        { "declare", ovsdb_execute_declare },
+        { "comment", ovsdb_execute_comment },
     };
 
     size_t i;
@@ -133,8 +139,8 @@ ovsdb_execute(struct ovsdb *db, const struct json *params,
             if (executor) {
                 error = executor(&x, &parser, result);
             } else {
-                error = ovsdb_syntax_error(operation, "unknown operation",
-                                           "No operation \"%s\"", op_name);
+                ovsdb_parser_raise_error(&parser, "No operation \"%s\"",
+                                         op_name);
             }
         } else {
             assert(ovsdb_parser_has_error(&parser));
@@ -168,8 +174,7 @@ ovsdb_execute(struct ovsdb *db, const struct json *params,
     }
 
     if (!error) {
-        /* Commit transaction.  Bail if commit encounters error.  */
-        error = do_commit(&x);
+        error = ovsdb_txn_commit(x.txn, x.durable);
         if (error) {
             json_array_add(results, ovsdb_error_to_json(error));
         }
@@ -208,38 +213,6 @@ ovsdb_execute_abort(struct ovsdb_execution *x UNUSED,
     return ovsdb_error("aborted", "aborted by request");
 }
 
-static struct ovsdb_error *
-do_commit(struct ovsdb_execution *x)
-{
-    if (x->db->file) {
-        struct ovsdb_error *error;
-        struct json *json;
-
-        json = ovsdb_txn_to_json(x->txn);
-        if (!json) {
-            /* Nothing to commit. */
-            return NULL;
-        }
-
-        error = ovsdb_file_write(x->db->file, json);
-        json_destroy(json);
-        if (error) {
-            return ovsdb_wrap_error(error, "writing transaction failed");
-        }
-
-        if (x->durable) {
-            error = ovsdb_file_commit(x->db->file);
-            if (error) {
-                return ovsdb_wrap_error(error,
-                                        "committing transaction failed");
-            }
-        }
-    }
-
-    ovsdb_txn_commit(x->txn);
-    return NULL;
-}
-
 static struct ovsdb_table *
 parse_table(struct ovsdb_execution *x,
             struct ovsdb_parser *parser, const char *member)
@@ -300,19 +273,38 @@ ovsdb_execute_insert(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     struct ovsdb_row *row = NULL;
     const struct json *uuid_name;
     struct ovsdb_error *error;
+    struct uuid row_uuid;
 
     table = parse_table(x, parser, "table");
     uuid_name = ovsdb_parser_member(parser, "uuid-name", OP_ID | OP_OPTIONAL);
     error = ovsdb_parser_get_error(parser);
+
+    if (uuid_name) {
+        struct ovsdb_symbol *symbol;
+
+        symbol = ovsdb_symbol_table_get(x->symtab, json_string(uuid_name));
+        if (symbol) {
+            if (symbol->used) {
+                return ovsdb_syntax_error(uuid_name, "duplicate uuid-name",
+                                          "This \"uuid-name\" appeared on an "
+                                          "earlier \"insert\" operation.");
+            }
+            row_uuid = symbol->uuid;
+            symbol->used = true;
+        } else {
+            uuid_generate(&row_uuid);
+            ovsdb_symbol_table_put(x->symtab, json_string(uuid_name),
+                                   &row_uuid, true);
+        }
+    } else {
+        uuid_generate(&row_uuid);
+    }
+
     if (!error) {
         error = parse_row(parser, "row", table, x->symtab, &row, NULL);
     }
     if (!error) {
-        uuid_generate(ovsdb_row_get_uuid_rw(row));
-        if (uuid_name) {
-            ovsdb_symbol_table_put(x->symtab, json_string(uuid_name),
-                                   ovsdb_row_get_uuid(row));
-        }
+        *ovsdb_row_get_uuid_rw(row) = row_uuid;
         ovsdb_txn_row_insert(x->txn, row);
         json_object_put(result, "uuid",
                         ovsdb_datum_to_json(&row->fields[OVSDB_COL_UUID],
@@ -427,6 +419,64 @@ ovsdb_execute_update(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     return error;
 }
 
+struct mutate_row_cbdata {
+    size_t n_matches;
+    struct ovsdb_txn *txn;
+    const struct ovsdb_mutation_set *mutations;
+};
+
+static bool
+mutate_row_cb(const struct ovsdb_row *row, void *mr_)
+{
+    struct mutate_row_cbdata *mr = mr_;
+
+    mr->n_matches++;
+    ovsdb_mutation_set_execute(ovsdb_txn_row_modify(mr->txn, row),
+                               mr->mutations);
+
+    return true;
+}
+
+struct ovsdb_error *
+ovsdb_execute_mutate(struct ovsdb_execution *x, struct ovsdb_parser *parser,
+                     struct json *result)
+{
+    struct ovsdb_table *table;
+    const struct json *where;
+    const struct json *mutations_json;
+    struct ovsdb_condition condition = OVSDB_CONDITION_INITIALIZER;
+    struct ovsdb_mutation_set mutations = OVSDB_MUTATION_SET_INITIALIZER;
+    struct ovsdb_row *row = NULL;
+    struct mutate_row_cbdata mr;
+    struct ovsdb_error *error;
+
+    table = parse_table(x, parser, "table");
+    where = ovsdb_parser_member(parser, "where", OP_ARRAY);
+    mutations_json = ovsdb_parser_member(parser, "mutations", OP_ARRAY);
+    error = ovsdb_parser_get_error(parser);
+    if (!error) {
+        error = ovsdb_mutation_set_from_json(table->schema, mutations_json,
+                                             x->symtab, &mutations);
+    }
+    if (!error) {
+        error = ovsdb_condition_from_json(table->schema, where, x->symtab,
+                                          &condition);
+    }
+    if (!error) {
+        mr.n_matches = 0;
+        mr.txn = x->txn;
+        mr.mutations = &mutations;
+        ovsdb_query(table, &condition, mutate_row_cb, &mr);
+        json_object_put(result, "count", json_integer_create(mr.n_matches));
+    }
+
+    ovsdb_row_destroy(row);
+    ovsdb_mutation_set_destroy(&mutations);
+    ovsdb_condition_destroy(&condition);
+
+    return error;
+}
+
 struct delete_row_cbdata {
     size_t n_matches;
     const struct ovsdb_table *table;
@@ -611,3 +661,44 @@ ovsdb_execute_wait(struct ovsdb_execution *x, struct ovsdb_parser *parser,
 
     return error;
 }
+
+static struct ovsdb_error *
+ovsdb_execute_declare(struct ovsdb_execution *x, struct ovsdb_parser *parser,
+                      struct json *result)
+{
+    const struct json *uuid_name;
+    struct uuid uuid;
+
+    uuid_name = ovsdb_parser_member(parser, "uuid-name", OP_ID);
+    if (!uuid_name) {
+        return NULL;
+    }
+
+    if (ovsdb_symbol_table_get(x->symtab, json_string(uuid_name))) {
+        return ovsdb_syntax_error(uuid_name, "duplicate uuid-name",
+                                  "This \"uuid-name\" appeared on an "
+                                  "earlier \"declare\" or \"insert\" "
+                                  "operation.");
+    }
+
+    uuid_generate(&uuid);
+    ovsdb_symbol_table_put(x->symtab, json_string(uuid_name), &uuid, false);
+    json_object_put(result, "uuid", json_string_create_nocopy(
+                        xasprintf(UUID_FMT, UUID_ARGS(&uuid))));
+    return NULL;
+}
+
+static struct ovsdb_error *
+ovsdb_execute_comment(struct ovsdb_execution *x, struct ovsdb_parser *parser,
+                      struct json *result UNUSED)
+{
+    const struct json *comment;
+
+    comment = ovsdb_parser_member(parser, "comment", OP_STRING);
+    if (!comment) {
+        return NULL;
+    }
+    ovsdb_txn_add_comment(x->txn, json_string(comment));
+
+    return NULL;
+}