diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c
index 46298cb47..df445d775 100644
--- a/lib/ovsdb-data.c
+++ b/lib/ovsdb-data.c
@@ -219,13 +219,13 @@ ovsdb_atom_parse_uuid(struct uuid *uuid, const struct json *json,
error1 = unwrap_json(json, "named-uuid", JSON_STRING, &value);
if (!error1) {
const char *name = json_string(value);
- const struct uuid *named_uuid;
+ const struct ovsdb_symbol *symbol;
ovsdb_error_destroy(error0);
- named_uuid = ovsdb_symbol_table_get(symtab, name);
- if (named_uuid) {
- *uuid = *named_uuid;
+ symbol = ovsdb_symbol_table_get(symtab, name);
+ if (symbol) {
+ *uuid = symbol->uuid;
return NULL;
} else {
return ovsdb_syntax_error(json, NULL,
@@ -728,7 +728,8 @@ ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *symtab)
struct shash_node *node, *next;
SHASH_FOR_EACH_SAFE (node, next, &symtab->sh) {
- free(node->data);
+ struct ovsdb_symbol *symbol = node->data;
+ free(symbol);
shash_delete(&symtab->sh, node);
}
shash_destroy(&symtab->sh);
@@ -736,7 +737,7 @@ ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *symtab)
}
}
-const struct uuid *
+struct ovsdb_symbol *
ovsdb_symbol_table_get(const struct ovsdb_symbol_table *symtab,
const char *name)
{
@@ -745,12 +746,13 @@ ovsdb_symbol_table_get(const struct ovsdb_symbol_table *symtab,
void
ovsdb_symbol_table_put(struct ovsdb_symbol_table *symtab, const char *name,
- const struct uuid *uuid)
+ const struct uuid *uuid, bool used)
{
- struct uuid *entry = shash_find_data(&symtab->sh, name);
- if (!entry) {
- shash_add(&symtab->sh, name, xmemdup(uuid, sizeof *uuid));
- } else {
- *entry = *uuid;
- }
+ struct ovsdb_symbol *symbol;
+
+ assert(!ovsdb_symbol_table_get(symtab, name));
+ symbol = xmalloc(sizeof *symbol);
+ symbol->uuid = *uuid;
+ symbol->used = used;
+ shash_add(&symtab->sh, name, symbol);
}
diff --git a/lib/ovsdb-data.h b/lib/ovsdb-data.h
index 35c4e3075..b31aa5d49 100644
--- a/lib/ovsdb-data.h
+++ b/lib/ovsdb-data.h
@@ -118,11 +118,16 @@ ovsdb_datum_conforms_to_type(const struct ovsdb_datum *datum,
/* A table mapping from names to data items. Currently the data items are
* always UUIDs; perhaps this will be expanded in the future. */
+struct ovsdb_symbol {
+ struct uuid uuid; /* The UUID that the symbol represents. */
+ bool used; /* Already used as row UUID? */
+};
+
struct ovsdb_symbol_table *ovsdb_symbol_table_create(void);
void ovsdb_symbol_table_destroy(struct ovsdb_symbol_table *);
-const struct uuid *ovsdb_symbol_table_get(const struct ovsdb_symbol_table *,
- const char *name);
+struct ovsdb_symbol *ovsdb_symbol_table_get(const struct ovsdb_symbol_table *,
+ const char *name);
void ovsdb_symbol_table_put(struct ovsdb_symbol_table *, const char *name,
- const struct uuid *);
+ const struct uuid *, bool used);
#endif /* ovsdb-data.h */
diff --git a/ovsdb/SPECS b/ovsdb/SPECS
index 17b0840ca..93db15d4c 100644
--- a/ovsdb/SPECS
+++ b/ovsdb/SPECS
@@ -599,7 +599,7 @@ Request object members:
"op": "insert" required
"table":
required
"row": required
- "uuid-name": optional
+ "uuid-name": optional
Result object members:
@@ -611,10 +611,31 @@ Semantics:
for all the columns in "table", those columns receive default
values.
- The new row receives a new, randomly generated UUID, which is
- returned as the "uuid" member of the result. If "uuid-name" is
- supplied, then the UUID is made available under that name to this
- operation and later operations within the same transaction.
+ If "uuid-name" is not supplied, the new row receives a new,
+ randomly generated UUID.
+
+ If "uuid-name" is supplied, then it is an error if has
+ previously appeared as the "uuid-name" in an "insert" operation.
+
+ If "uuid-name" is supplied and its previously appeared as the
+ "uuid-name" in a "declare" operation, then the new row receives
+ the UUID associated with that "uuid-name".
+
+ If "uuid-name" is supplied and its has not previously
+ appeared as the "uuid-name" in a "declare" operation, then the new
+ row also receives a new, randomly generated UUID. This UUID is
+ also made available under that name to this operation and later
+ operations within the same transaction.
+
+ The UUID for the new row is returned as the "uuid" member of the
+ result.
+
+Errors:
+
+ "error": "duplicate uuid-name"
+
+ The same "uuid-name" appeared on an earlier "insert" operation
+ within this transaction.
select
......
@@ -797,3 +818,37 @@ Errors:
"error": "aborted"
This operation always fails with this error.
+
+declare
+.......
+
+Request object members:
+
+ "op": "declare" required
+ "uuid-name": required
+
+Result object members:
+
+ none
+
+Semantics:
+
+ Predeclares a UUID named that may be referenced in later
+ operations as ["named-uuid", ] or (at most once) in an
+ "insert" operation as "uuid-name".
+
+ It is an error if has appeared as the "uuid-name" in a prior
+ "insert" or "declare" operation within this transaction.
+
+ The generated UUID is returned as the "uuid" member of the result.
+
+Result object members:
+
+ "uuid":
+
+Errors:
+
+ "error": "duplicate uuid-name"
+
+ The same "uuid-name" appeared on an earlier "insert" or
+ "declare" operation within this transaction.
diff --git a/ovsdb/execution.c b/ovsdb/execution.c
index 0bfe86fb3..932bee238 100644
--- a/ovsdb/execution.c
+++ b/ovsdb/execution.c
@@ -54,6 +54,7 @@ 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 *
lookup_executor(const char *name)
@@ -71,6 +72,7 @@ lookup_executor(const char *name)
{ "wait", ovsdb_execute_wait },
{ "commit", ovsdb_execute_commit },
{ "abort", ovsdb_execute_abort },
+ { "declare", ovsdb_execute_declare },
};
size_t i;
@@ -272,9 +274,25 @@ ovsdb_execute_insert(struct ovsdb_execution *x, struct ovsdb_parser *parser,
uuid_name = ovsdb_parser_member(parser, "uuid-name", OP_ID | OP_OPTIONAL);
error = ovsdb_parser_get_error(parser);
- uuid_generate(&row_uuid);
if (uuid_name) {
- ovsdb_symbol_table_put(x->symtab, json_string(uuid_name), &row_uuid);
+ 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) {
@@ -580,3 +598,29 @@ 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;
+}
diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
index cf9f1ba37..a1717b8c4 100644
--- a/tests/ovsdb-idl.at
+++ b/tests/ovsdb-idl.at
@@ -143,18 +143,18 @@ OVSDB_CHECK_IDL([self-linking idl, consistent ops],
"table": "link1",
"row": {"i": 0, "k": ["named-uuid", "self"]},
"uuid-name": "self"}]' \
- '[{"op": "insert",
+ '[{"op": "declare",
+ "uuid-name": "row1"},
+ {"op": "declare",
+ "uuid-name": "row2"},
+ {"op": "insert",
"table": "link1",
- "row": {"i": 1},
+ "row": {"i": 1, "k": ["named-uuid", "row2"]},
"uuid-name": "row1"},
{"op": "insert",
"table": "link1",
"row": {"i": 2, "k": ["named-uuid", "row1"]},
- "uuid-name": "row2"},
- {"op": "update",
- "table": "link1",
- "where": [["i", "==", 1]],
- "row": {"k": ["named-uuid", "row2"]}}]' \
+ "uuid-name": "row2"}]' \
'[{"op": "update",
"table": "link1",
"where": [["i", "==", 1]],
@@ -166,7 +166,7 @@ OVSDB_CHECK_IDL([self-linking idl, consistent ops],
[[000: empty
001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
002: i=0 k=0 ka=[] l2= uuid=<0>
-003: {"error":null,"result":[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]},{"count":1}]}
+003: {"error":null,"result":[{"uuid":"<1>"},{"uuid":"<2>"},{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
004: i=0 k=0 ka=[] l2= uuid=<0>
004: i=1 k=2 ka=[] l2= uuid=<1>
004: i=2 k=1 ka=[] l2= uuid=<2>
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index fb13df9c3..9819d03da 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -1346,7 +1346,8 @@ parse_uuids(const struct json *json, struct ovsdb_symbol_table *symtab,
if (json->type == JSON_STRING && uuid_from_string(&uuid, json->u.string)) {
char *name = xasprintf("#%d#", *n);
- ovsdb_symbol_table_put(symtab, name, &uuid);
+ fprintf(stderr, "%s = "UUID_FMT"\n", name, UUID_ARGS(&uuid));
+ ovsdb_symbol_table_put(symtab, name, &uuid, false);
free(name);
*n += 1;
} else if (json->type == JSON_ARRAY) {
@@ -1368,12 +1369,12 @@ static void
substitute_uuids(struct json *json, const struct ovsdb_symbol_table *symtab)
{
if (json->type == JSON_STRING) {
- const struct uuid *uuid;
+ const struct ovsdb_symbol *symbol;
- uuid = ovsdb_symbol_table_get(symtab, json->u.string);
- if (uuid) {
+ symbol = ovsdb_symbol_table_get(symtab, json->u.string);
+ if (symbol) {
free(json->u.string);
- json->u.string = xasprintf(UUID_FMT, UUID_ARGS(uuid));
+ json->u.string = xasprintf(UUID_FMT, UUID_ARGS(&symbol->uuid));
}
} else if (json->type == JSON_ARRAY) {
size_t i;