tree data UPDATE refactor default NP container updates
Make sure specific functions are always used so that
it is performed in the same way and always.
Fixes #2315
diff --git a/src/parser_common.c b/src/parser_common.c
index 0d03229..9bd2274 100644
--- a/src/parser_common.c
+++ b/src/parser_common.c
@@ -420,7 +420,7 @@
}
/* update dflt flag for all parent NP containers */
- lyd_cont_set_dflt(lyd_parent(node));
+ lyd_np_cont_dflt_set(lyd_parent(node));
break;
}
diff --git a/src/tree_data.c b/src/tree_data.c
index 8488401..b53a1a1 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -545,7 +545,6 @@
void
lyd_insert_after_node(struct lyd_node **first_sibling_p, struct lyd_node *sibling, struct lyd_node *node)
{
- struct lyd_node_inner *par;
struct lyd_node *first_sibling;
assert(!node->next && (node->prev == node) && (sibling != node));
@@ -571,19 +570,15 @@
sibling->next = node;
node->parent = sibling->parent;
- for (par = node->parent; par; par = par->parent) {
- if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
- /* remove default flags from NP containers */
- par->flags &= ~LYD_DEFAULT;
- }
+ if (!(node->flags & LYD_DEFAULT)) {
+ /* remove default flags from NP containers */
+ lyd_np_cont_dflt_del(lyd_parent(node));
}
}
void
lyd_insert_before_node(struct lyd_node *sibling, struct lyd_node *node)
{
- struct lyd_node_inner *par;
-
assert(!node->next && (node->prev == node) && (sibling != node));
node->next = sibling;
@@ -599,11 +594,9 @@
}
node->parent = sibling->parent;
- for (par = node->parent; par; par = par->parent) {
- if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
- /* remove default flags from NP containers */
- par->flags &= ~LYD_DEFAULT;
- }
+ if (!(node->flags & LYD_DEFAULT)) {
+ /* remove default flags from NP containers */
+ lyd_np_cont_dflt_del(lyd_parent(node));
}
}
@@ -628,11 +621,9 @@
par->child = node;
node->parent = par;
- for ( ; par; par = par->parent) {
- if ((par->flags & LYD_DEFAULT) && !(node->flags & LYD_DEFAULT)) {
- /* remove default flags from NP containers */
- par->flags &= ~LYD_DEFAULT;
- }
+ if (!(node->flags & LYD_DEFAULT)) {
+ /* remove default flags from NP containers */
+ lyd_np_cont_dflt_del(parent);
}
}
@@ -1192,7 +1183,7 @@
}
/* check for NP container whether its last non-default node is not being unlinked */
- lyd_cont_set_dflt(lyd_parent(node));
+ lyd_np_cont_dflt_set(lyd_parent(node));
node->parent = NULL;
}
@@ -1285,9 +1276,8 @@
}
/* remove default flags from NP containers */
- while (clear_dflt && parent && (parent->schema->nodetype == LYS_CONTAINER) && (parent->flags & LYD_DEFAULT)) {
- parent->flags &= ~LYD_DEFAULT;
- parent = lyd_parent(parent);
+ if (clear_dflt) {
+ lyd_np_cont_dflt_del(parent);
}
}
@@ -2496,7 +2486,6 @@
const struct lyd_node *child_src, *tmp, *sibling_src;
struct lyd_node *match_trg, *dup_src, *elem, *leader;
struct lyd_node_opaq *opaq_trg, *opaq_src;
- struct lysc_type *type;
const struct lysc_node *schema;
struct ly_ht *child_dup_inst = NULL;
LY_ERR r;
@@ -2546,19 +2535,15 @@
&opaq_trg->val_prefix_data);
}
} else if ((match_trg->schema->nodetype == LYS_LEAF) &&
- lyd_compare_single(sibling_src, match_trg, LYD_COMPARE_DEFAULTS)) {
- /* since they are different, they cannot both be default */
- assert(!(sibling_src->flags & LYD_DEFAULT) || !(match_trg->flags & LYD_DEFAULT));
+ ((options & LYD_MERGE_DEFAULTS) || !(sibling_src->flags & LYD_DEFAULT))) {
+ /* update value */
+ r = lyd_change_term_val(match_trg, &((struct lyd_node_term *)sibling_src)->value, 0,
+ sibling_src->flags & LYD_DEFAULT);
+ LY_CHECK_RET(r && (r != LY_EEXIST) && (r != LY_ENOT), r);
- /* update value (or only LYD_DEFAULT flag) only if flag set or the source node is not default */
- if ((options & LYD_MERGE_DEFAULTS) || !(sibling_src->flags & LYD_DEFAULT)) {
- type = ((struct lysc_node_leaf *)match_trg->schema)->type;
- type->plugin->free(LYD_CTX(match_trg), &((struct lyd_node_term *)match_trg)->value);
- LY_CHECK_RET(type->plugin->duplicate(LYD_CTX(match_trg), &((struct lyd_node_term *)sibling_src)->value,
- &((struct lyd_node_term *)match_trg)->value));
-
- /* copy flags and add LYD_NEW */
- match_trg->flags = sibling_src->flags | ((options & LYD_MERGE_WITH_FLAGS) ? 0 : LYD_NEW);
+ if (options & LYD_MERGE_WITH_FLAGS) {
+ /* keep the exact same flags */
+ match_trg->flags = sibling_src->flags;
}
} else if ((match_trg->schema->nodetype & LYS_ANYDATA) && lyd_compare_single(sibling_src, match_trg, 0)) {
/* update value */
diff --git a/src/tree_data_common.c b/src/tree_data_common.c
index f480a5a..14b558a 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief Parsing and validation common functions for data trees
*
- * Copyright (c) 2015 - 2022 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -1157,35 +1157,6 @@
return 0;
}
-void
-lyd_cont_set_dflt(struct lyd_node *node)
-{
- const struct lyd_node *child;
-
- while (node) {
- if (!node->schema || (node->flags & LYD_DEFAULT) || !lysc_is_np_cont(node->schema)) {
- /* not a non-dflt NP container */
- break;
- }
-
- LY_LIST_FOR(lyd_child(node), child) {
- if (!(child->flags & LYD_DEFAULT)) {
- break;
- }
- }
- if (child) {
- /* explicit child, no dflt change */
- break;
- }
-
- /* set the dflt flag */
- node->flags |= LYD_DEFAULT;
-
- /* check all parent containers */
- node = lyd_parent(node);
- }
-}
-
/**
* @brief Comparison callback to match schema node with a schema of a data node.
*
@@ -1301,6 +1272,44 @@
}
}
+void
+lyd_np_cont_dflt_set(struct lyd_node *parent)
+{
+ const struct lyd_node *child;
+
+ while (parent) {
+ if (!parent->schema || (parent->flags & LYD_DEFAULT) || !lysc_is_np_cont(parent->schema)) {
+ /* not a non-dflt NP container */
+ break;
+ }
+
+ LY_LIST_FOR(lyd_child(parent), child) {
+ if (!(child->flags & LYD_DEFAULT)) {
+ break;
+ }
+ }
+ if (child) {
+ /* explicit child, no dflt change */
+ break;
+ }
+
+ /* set the dflt flag */
+ parent->flags |= LYD_DEFAULT;
+
+ /* check all parent containers */
+ parent = lyd_parent(parent);
+ }
+}
+
+void
+lyd_np_cont_dflt_del(struct lyd_node *parent)
+{
+ while (parent && (parent->flags & LYD_DEFAULT)) {
+ parent->flags &= ~LYD_DEFAULT;
+ parent = lyd_parent(parent);
+ }
+}
+
LY_ERR
ly_nested_ext_schema(const struct lyd_node *parent, const struct lysc_node *sparent, const char *prefix,
size_t prefix_len, LY_VALUE_FORMAT format, void *prefix_data, const char *name, size_t name_len,
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index 358528c..b4a8d25 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -4,7 +4,7 @@
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief internal functions for YANG schema trees.
*
- * Copyright (c) 2015 - 2023 CESNET, z.s.p.o.
+ * Copyright (c) 2015 - 2024 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
@@ -118,13 +118,6 @@
const struct lys_module *lyd_data_next_module(struct lyd_node **next, struct lyd_node **first);
/**
- * @brief Set dflt flag for a NP container if applicable, recursively for parents.
- *
- * @param[in] node Node whose criteria for the dflt flag has changed.
- */
-void lyd_cont_set_dflt(struct lyd_node *node);
-
-/**
* @brief Search in the given siblings (NOT recursively) for the first schema node data instance.
* Uses hashes - should be used whenever possible for best performance.
*
@@ -148,6 +141,20 @@
void lyd_del_move_root(struct lyd_node **root, const struct lyd_node *to_del, const struct lys_module *mod);
/**
+ * @brief After adding a default child, check the node and all of its parent NP containers and set their dflt flag.
+ *
+ * @param[in] parent Changed first parent to check.
+ */
+void lyd_np_cont_dflt_set(struct lyd_node *parent);
+
+/**
+ * @brief After adding a non-default child, remove the dflt flag from parent and other parent NP containers.
+ *
+ * @param[in] parent Changed first parent to update.
+ */
+void lyd_np_cont_dflt_del(struct lyd_node *parent);
+
+/**
* @brief Try to get schema node for data with a parent based on an extension instance.
*
* @param[in] parent Parsed parent data node. Set if @p sparent is NULL.
@@ -345,6 +352,23 @@
LY_VALUE_FORMAT format, void *val_prefix_data, uint32_t hints, struct lyd_node **node);
/**
+ * @brief Change the value of a term (leaf or leaf-list) node.
+ *
+ * Node changed this way is always considered explicitly set, meaning its default flag
+ * is always cleared.
+ *
+ * @param[in] term Term node to change.
+ * @param[in] val New value to use.
+ * @param[in] use_val Whether @p val can be used and spent or should only be duplicated.
+ * @param[in] is_dflt Whether @p val is a default value or not.
+ * @return LY_SUCCESS if value was changed,
+ * @return LY_EEXIST if value was the same and only the default flag was cleared,
+ * @return LY_ENOT if the values were equal and no change occured,
+ * @return LY_ERR value on other errors.
+ */
+LY_ERR lyd_change_term_val(struct lyd_node *term, struct lyd_value *val, ly_bool use_val, ly_bool is_dflt);
+
+/**
* @brief Check the existence and create any non-existing implicit children.
*
* @param[in] parent Parent of the potential default values, NULL for top-level siblings.
diff --git a/src/tree_data_new.c b/src/tree_data_new.c
index cd5d63b..26e408d 100644
--- a/src/tree_data_new.c
+++ b/src/tree_data_new.c
@@ -1243,14 +1243,15 @@
*
* Reinserting ensures that the node is in the correct position and the data instances remain properly ordered.
*
- * @param[in] term Term node to change. If it is a key, the parental list is inserted again.
+ * @param[in] term Term node to change. If it is a key, the parent list is reinserted.
* @param[in] val New value for @p term.
- * @return LY_SUCCESS on success.
+ * @param[in] use_val Whether @p val can be used and spent or should only be duplicated.
+ * @return LY_ERR value.
*/
static LY_ERR
-lyd_change_node_value(struct lyd_node_term *term, struct lyd_value *val)
+lyd_change_node_value(struct lyd_node_term *term, struct lyd_value *val, ly_bool use_val)
{
- LY_ERR ret = LY_SUCCESS;
+ LY_ERR rc = LY_SUCCESS;
struct lyd_node *target, *first;
if (term->schema->nodetype == LYS_LEAFLIST) {
@@ -1260,33 +1261,115 @@
} else {
/* just change the value */
term->value.realtype->plugin->free(LYD_CTX(term), &term->value);
- term->value = *val;
+ if (use_val) {
+ term->value = *val;
+ } else {
+ rc = ((struct lysc_node_leaf *)term->schema)->type->plugin->duplicate(LYD_CTX(term), val, &term->value);
+ }
+
/* leaf that is not a key, its value is not used for its hash so it does not change */
- return LY_SUCCESS;
+ return rc;
}
if (!LYD_NODE_IS_ALONE(target) && lyds_is_supported(target)) {
/* changing the value may cause a change in the order */
first = lyd_first_sibling(target);
first = first == target ? first->next : first;
+
/* unlink hash and unlink the target node in the lyds tree */
lyd_unlink_tree(target);
+
/* change value */
term->value.realtype->plugin->free(LYD_CTX(term), &term->value);
- term->value = *val;
+ if (use_val) {
+ term->value = *val;
+ } else {
+ rc = ((struct lysc_node_leaf *)term->schema)->type->plugin->duplicate(LYD_CTX(term), val, &term->value);
+ }
+
/* reinserting */
lyd_insert_node(NULL, &first, target, LYD_INSERT_NODE_DEFAULT);
} else {
/* unlink hash */
lyd_unlink_hash(target);
+
/* change value */
term->value.realtype->plugin->free(LYD_CTX(term), &term->value);
- term->value = *val;
+ if (use_val) {
+ term->value = *val;
+ } else {
+ rc = ((struct lysc_node_leaf *)term->schema)->type->plugin->duplicate(LYD_CTX(term), val, &term->value);
+ }
}
- lyd_hash(target);
- ret = lyd_insert_hash(target);
- return ret;
+ lyd_hash(target);
+ rc = lyd_insert_hash(target);
+
+ return rc;
+}
+
+LY_ERR
+lyd_change_term_val(struct lyd_node *term, struct lyd_value *val, ly_bool use_val, ly_bool is_dflt)
+{
+ LY_ERR rc = LY_SUCCESS;
+ struct lysc_type *type;
+ struct lyd_node_term *t;
+ ly_bool dflt_change, val_change;
+
+ t = (struct lyd_node_term *)term;
+ type = ((struct lysc_node_leaf *)term->schema)->type;
+
+ /* compare original and new value */
+ if (type->plugin->compare(LYD_CTX(term), &t->value, val)) {
+ /* since they are different, they cannot both be default */
+ assert(!(term->flags & LYD_DEFAULT) || !is_dflt);
+
+ /* values differ, switch them */
+ LY_CHECK_RET(lyd_change_node_value(t, val, use_val));
+ val_change = 1;
+ } else {
+ /* same values, free the new stored one */
+ if (use_val) {
+ type->plugin->free(LYD_CTX(term), val);
+ }
+ val_change = 0;
+ }
+
+ /* clear links to leafref nodes */
+ if (val_change && (ly_ctx_get_options(LYD_CTX(term)) & LY_CTX_LEAFREF_LINKING)) {
+ lyd_free_leafref_nodes(t);
+ }
+
+ /* update flags */
+ if (val_change) {
+ term->flags |= LYD_NEW;
+ }
+ if ((term->flags & LYD_DEFAULT) && !is_dflt) {
+ /* remove dflt flag */
+ term->flags &= ~LYD_DEFAULT;
+
+ /* remove parent dflt flag */
+ lyd_np_cont_dflt_del(lyd_parent(term));
+
+ dflt_change = 1;
+ } else if (!(term->flags & LYD_DEFAULT) && is_dflt) {
+ /* add dflt flag */
+ term->flags |= LYD_DEFAULT;
+
+ /* add parent dflt flag */
+ lyd_np_cont_dflt_set(lyd_parent(term));
+
+ dflt_change = 1;
+ } else {
+ dflt_change = 0;
+ }
+
+ if (!val_change) {
+ /* only default flag change or no change */
+ rc = dflt_change ? LY_EEXIST : LY_ENOT;
+ } /* else value changed, LY_SUCCESS */
+
+ return rc;
}
/**
@@ -1307,68 +1390,20 @@
static LY_ERR
_lyd_change_term(struct lyd_node *term, const void *value, size_t value_len, LY_VALUE_FORMAT format)
{
- LY_ERR ret = LY_SUCCESS;
- struct lysc_type *type;
- struct lyd_node_term *t;
- struct lyd_node *parent;
+ LY_ERR r;
struct lyd_value val;
- ly_bool dflt_change, val_change;
assert(term && term->schema && (term->schema->nodetype & LYD_NODE_TERM));
- t = (struct lyd_node_term *)term;
- type = ((struct lysc_node_leaf *)term->schema)->type;
-
/* parse the new value */
LOG_LOCSET(term->schema, term);
- ret = lyd_value_store(LYD_CTX(term), &val, type, value, value_len, 0, 0, NULL, format, NULL, LYD_HINT_DATA,
- term->schema, NULL);
+ r = lyd_value_store(LYD_CTX(term), &val, ((struct lysc_node_leaf *)term->schema)->type, value, value_len, 0, 0,
+ NULL, format, NULL, LYD_HINT_DATA, term->schema, NULL);
LOG_LOCBACK(1, 1);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_RET(r);
- /* compare original and new value */
- if (type->plugin->compare(LYD_CTX(term), &t->value, &val)) {
- /* values differ, switch them */
- lyd_change_node_value(t, &val);
- /* make the node non-validated */
- term->flags &= LYD_NEW;
- val_change = 1;
- } else {
- /* same values, free the new stored one */
- type->plugin->free(LYD_CTX(term), &val);
- val_change = 0;
- }
-
- /* clear links to leafref nodes */
- if (ly_ctx_get_options(LYD_CTX(term)) & LY_CTX_LEAFREF_LINKING) {
- lyd_free_leafref_nodes(t);
- }
-
- /* always clear the default flag */
- if (term->flags & LYD_DEFAULT) {
- for (parent = term; parent; parent = lyd_parent(parent)) {
- parent->flags &= ~LYD_DEFAULT;
- }
- /* make the node non-validated */
- term->flags &= LYD_NEW;
- dflt_change = 1;
- } else {
- dflt_change = 0;
- }
-
- /* return value */
- if (!val_change) {
- if (dflt_change) {
- /* only default flag change */
- ret = LY_EEXIST;
- } else {
- /* no change */
- ret = LY_ENOT;
- }
- } /* else value changed, LY_SUCCESS */
-
-cleanup:
- return ret;
+ /* change it */
+ return lyd_change_term_val(term, &val, 1, 0);
}
LIBYANG_API_DEF LY_ERR
diff --git a/src/validation.c b/src/validation.c
index 4f91ab3..0617b5a 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -1640,7 +1640,7 @@
LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
/* set default for containers */
- lyd_cont_set_dflt(node);
+ lyd_np_cont_dflt_set(node);
}
cleanup: