ovsdb: Add simple constraints.
[cascardo/ovs.git] / ovsdb / execution.c
index 932bee2..7cf45f6 100644 (file)
@@ -1,4 +1,4 @@
-/* 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.
@@ -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"
@@ -50,11 +51,13 @@ typedef struct ovsdb_error *ovsdb_operation_executor(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,11 +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;
@@ -156,9 +161,11 @@ ovsdb_execute(struct ovsdb *db, const struct json *params,
             && timeout_msec) {
             ovsdb_txn_abort(x.txn);
             *timeout_msec = x.timeout_msec;
-            ovsdb_error_destroy(error);
+
+            json_destroy(result);
             json_destroy(results);
-            return NULL;
+            results = NULL;
+            goto exit;
         }
 
         /* Add result to array. */
@@ -181,6 +188,7 @@ ovsdb_execute(struct ovsdb *db, const struct json *params,
         json_array_add(results, json_null_create());
     }
 
+exit:
     ovsdb_error_destroy(error);
     ovsdb_symbol_table_destroy(x.symtab);
 
@@ -298,13 +306,37 @@ ovsdb_execute_insert(struct ovsdb_execution *x, struct ovsdb_parser *parser,
     if (!error) {
         error = parse_row(parser, "row", table, x->symtab, &row, NULL);
     }
+    if (!error) {
+        /* Check constraints for columns not included in "row", in case the
+         * default values do not satisfy the constraints.  We could check only
+         * the columns that have their default values by supplying an
+         * ovsdb_column_set to parse_row() above, but I suspect that this is
+         * cheaper.  */
+        const struct shash_node *node;
+
+        SHASH_FOR_EACH (node, &table->schema->columns) {
+            const struct ovsdb_column *column = node->data;
+            const struct ovsdb_datum *datum = &row->fields[column->index];
+
+            /* If there are 0 keys or pairs, there's nothing to check.
+             * If there is 1, it might be a default value.
+             * If there are more, it can't be a default value, so the value has
+             * already been checked. */
+            if (datum->n == 1) {
+                error = ovsdb_datum_check_constraints(datum, &column->type);
+                if (error) {
+                    ovsdb_row_destroy(row);
+                    break;
+                }
+            }
+        }
+    }
     if (!error) {
         *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],
                                             &ovsdb_type_uuid));
-        row = NULL;
     }
     return error;
 }
@@ -414,6 +446,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;
@@ -620,7 +710,25 @@ ovsdb_execute_declare(struct ovsdb_execution *x, struct ovsdb_parser *parser,
 
     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))));
+    json_object_put(result, "uuid",
+                    json_array_create_2(
+                        json_string_create("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;
 }