In an LDAP Modify request, what is the difference between replacing an attribute and deleting one of its values?
answer
- three change kinds, one entry
- values listed, or the whole attribute
- replace is an overwrite, not a merge
- an empty value list means remove
- all changes apply, or none do
basics
~20 sReplace discards every existing value of the attribute and installs the values listed in the change. Delete removes only the values listed and leaves the rest in place. Replace is an overwrite, never a merge.
solid answer
~40 sA `ModifyRequest` names one entry and carries an ordered list of changes, each an operation — `add (0)`, `delete (1)`, `replace (2)` — with an attribute and the values that change applies to. `add (0)` adds the listed values and creates the attribute if it is absent; a value already present earns `attributeOrValueExists (20)`. `delete (1)` removes exactly the listed values, and with no values listed removes the whole attribute; a value that is not there earns `noSuchAttribute (16)`. `replace (2)` throws away every existing value and installs the listed ones, creating the attribute if needed and removing it when the list is empty. The whole request is applied as one unit: if any change is refused, none is applied.
code
ldif · 11 linesdn: cn=Dana Okafor,ou=Staff,dc=example,dc=org
changetype: modify
delete: telephoneNumber
telephoneNumber: +44 20 7946 0102
-
dn: cn=Ali Nasser,ou=Staff,dc=example,dc=org
changetype: modify
replace: telephoneNumber
telephoneNumber: +44 20 7946 0199
-go deeper
Recall the three change kinds and that a Modify names one entry. Remember that replace overwrites the attribute rather than adding to it.
Explain what each change kind leaves behind, what an empty value list means for delete and for replace, and why the whole change list is applied as a single unit.
Show the read-modify-write race that a replace on a large multi-valued attribute invites, and that you reach for an add change with one value so the server does the merging.
Weigh idempotence against safety across a bulk job: adds fail on re-run, replaces succeed and destroy data, and the choice sets how a half-finished consolidation can be resumed.
## What a Modify request actually contains A `ModifyRequest` names **one** entry and carries an **ordered list of changes**. Each change is a pair: an operation — `add (0)`, `delete (1)` or `replace (2)` — and an attribute with the values that change applies to. There is no filter, no scope and no second entry. If a consolidation job has to touch four entries, that is four Modify requests. ## The three change kinds, precisely - **`add (0)`** — adds the listed values to the attribute, creating the attribute on the entry if it was not present. The values already there are untouched. Adding a value the entry already holds is refused with `attributeOrValueExists (20)`, which makes a bare add **non-idempotent**: re-running a partly finished job fails on the entries it already updated. - **`delete (1)`** — with values listed, removes exactly those values and leaves the rest. With **no** values listed, removes the attribute and everything in it. Naming a value the entry does not hold is refused with `noSuchAttribute (16)`. - **`replace (2)`** — discards **every** existing value of that attribute and installs the listed ones, creating the attribute if it was absent. With no values listed it removes the attribute, and unlike a delete it is not an error if the attribute was not there in the first place. ## Why replace is the dangerous one The single most common production defect on this operation is using `replace (2)` to *add* something to a multi-valued attribute. Merging three practices' address books, a person's entry may hold three `telephoneNumber` values and a group entry may hold two thousand `member` values. A `replace` carrying the one new value silently destroys the rest, and the reply is `success (0)` — the server did exactly what it was told. | you want to… | change to send | what survives | |---|---|---| | add one number to an entry that has three | `add (0)` with the new value | all four | | correct the only number an entry holds | `replace (2)` with the correct value | the one listed | | drop one number and keep the others | `delete (1)` naming that value | the others | | clear the attribute entirely | `delete (1)` or `replace (2)` with no values | nothing of that attribute | The second defect is the read-modify-write race that `replace` invites. A client that reads two thousand `member` values, appends one, and writes the whole list back will silently discard whatever another client added in between. An `add (0)` change naming only the new value has no such window, because the server merges rather than the client. ## What the server checks before applying anything 1. **Atomicity.** The change list is applied as a single unit. If the fourth of five changes is refused, the entry is left exactly as it was and one `resultCode` explains the refusal. Clients must not assume a partial application. 2. **The entry must still be valid afterwards.** The result of applying the whole list is checked against the rules that govern what the entry may hold; a refusal comes back as a code such as `objectClassViolation (65)` or `constraintViolation (19)`. 3. **The naming value is protected.** A change that would remove the value forming the entry's RDN is refused with `notAllowedOnRDN (67)`. Modify changes attribute *values*; changing the name of an entry is the ModifyDN operation's job, not this one's. ## The change nobody expects Beyond the three, RFC 4525 defines `increment (3)`, which adds a numeric amount to the attribute's existing value server-side instead of making the client read, add and write back. It removes the same race that `replace` invites, but it is an extension rather than part of the base operation set, and a server that has not implemented it refuses the whole Modify rather than quietly skipping that change. Portable code reads, computes and writes, and accepts the race or guards against it another way. ## The habit to take away Before sending any Modify, ask what the change *removes*. `add` removes nothing. `delete` removes what you named. `replace` removes everything you did not name — including values you never saw, put there by a system you do not own.
- One change in a five-change Modify is invalid. What state is the entry left in?Unchanged. The change list is applied as a single unit, so a refusal anywhere in it means nothing was applied, and the reply carries one `resultCode` for the whole request. Clients must not go looking for partially applied changes or try to work out how far the server got.
- How do you add one person to a group entry holding two thousand members?Send a Modify on the group entry with an `add (0)` change on `member` naming only that Distinguished Name. A `replace (2)` would install that one value and discard the other 1,999. The add is not idempotent — a second run earns `attributeOrValueExists (20)` — so treat that code as already-done.
- Can a Modify remove the value that forms the entry's RDN?No. A server refuses that change with `notAllowedOnRDN (67)`, because the entry would no longer hold the value it is named by. Changing an entry's naming value is the ModifyDN operation's job, and its `deleteoldrdn` field decides what happens to the old value.
Replacing an attribute is emptying the whole drawer and putting back only the folders in your hand; deleting a value is taking out one folder and leaving the drawer as it was.
saying these in an interview costs you the question
- Uses replace to add one value to a multi-valued attribute
- Thinks a delete change without a value list is a syntax error
- Expects a partly applied Modify when one change is refused
- Believes replace on an absent attribute is an error
- Says Modify can rename the entry by replacing its naming value
- Assumes the server merges the listed values with the existing ones