anoopj commented on code in PR #17822:
URL: https://github.com/apache/iceberg/pull/17822#discussion_r4236336803
##########
format/spec.md:
##########
@@ -655,6 +658,123 @@ Sorting floating-point numbers should produce the
following behavior: `-NaN` < `
A data or delete file is associated with a sort order by the sort order's id
within [a manifest](#manifests). Therefore, the table must declare all the sort
orders for lookup. A table could also be configured with a default sort order
id, indicating how the new data should be sorted by default. Writers should use
this default sort order to sort the data on write, but are not required to if
the default order is prohibitively expensive, as it would be for streaming
writes.
+### Constraints
+
+Constraints are added in v4 and are not supported in v3 or earlier.
+
+A **constraint** declares a condition that a table's rows are expected to
satisfy. Its definition is stored in table metadata. Each snapshot contains the
writer-reported status of each constraint that existed when the snapshot was
created; see [Constraint Validation](#constraint-validation).
+
+Three constraint types are defined:
+
+* `check` -- every row must satisfy a predicate
+* `unique` -- the values of a set of fields must be distinct across the rows
in which every field in the set is non-null; a row in which any field in the
set is null is not compared, so more than one such row may exist
+* `primary-key` -- the values of a set of fields must be distinct across all
rows and must not be null
+
+A constraint is stored separately from the table schema and must refer to
fields by field ID. Constraints may evolve independently from the schema, being
added, modified, or removed.
+
+#### Constraint Fields
+
+A constraint consists of the following fields:
+
+| Requirement | Field name | Type | Description |
+|-------------|---------------------------|-----------|-------------|
+| _required_ | **`constraint-id`** | `int` | ID of the constraint;
unique within the table |
+| _required_ | **`type`** | `string` | The constraint type:
`check`, `unique`, or `primary-key` |
+| _required_ | **`name`** | `string` | A name for the
constraint that is unique within the table. Names are for human consumption and
must not be used to identify a constraint in metadata |
+| _required_ | **`enforced`** | `boolean` | Whether writers must
only add rows that satisfy the constraint |
+| _required_ | **`timestamp-ms`** | `long` | Timestamp in
milliseconds from the unix epoch when the constraint was created or last
modified. The timestamp is informational and must not be used to determine
whether a constraint applies to a snapshot or whether it holds |
+| _optional_ | **`expression`** | `expression` | The predicate that
every row must satisfy, see [Check Constraint
Expressions](#check-constraint-expressions). Required for a `check` constraint
and must not be set for other types |
+| _optional_ | **`field-ids`** | `list<int>` | The list of field
IDs that the constraint applies to. Required for a `unique` or `primary-key`
constraint and must not be set for a `check` constraint |
+
+The fields that define what a constraint requires are embedded directly in the
constraint based on its `type`. Each type carries only the metadata that it
requires: a `check` constraint has an `expression` and must not declare
`field-ids`, and a `unique` or `primary-key` constraint has `field-ids` and
must not declare an `expression`. This keeps a single source of truth for the
fields that a constraint references.
+
+The `field-ids` of a `unique` or `primary-key` constraint must reference
primitive fields and must not reference fields within a `list` or a `map`.
Fields of type `float`, `double`, `geometry`, or `geography` must not be used
because Iceberg does not define equality for them. Fields of type `unknown`
must not be used because their values are always null.
+
+The fields of a `primary-key` constraint must be `required` and must not be
nested in an optional struct, so that the schema rules out null keys even when
the constraint is not enforced. These are the same restrictions that apply to
[identifier fields](#identifier-field-ids). The fields of a `unique` constraint
may be optional or nested in optional structs, because a row in which any field
is null is not compared.
+
+When a constraint is `enforced`, writers must only add rows they can prove
follow the constraint. A constraint that is not enforced can be written to by
any writer, regardless of their ability to prove that the constraint is
followed by new rows.
+
+When a commit is retried against a new parent snapshot, the rows that a writer
adds must still satisfy the table's enforced constraints. A `check` constraint
is evaluated for each row on its own, so a retry cannot change its result. A
`unique` or `primary-key` constraint compares rows to each other, so a writer
must verify the rows that it adds against the new parent; verifying them
against the original parent is not sufficient. A writer must also verify the
rows that it adds against any constraint that a concurrent commit added or
changed to enforced, and must recompute `constraint-statuses` from the new
parent.
Review Comment:
Concrete example: Suppose the table contains `(id=7, price=10)`. Updating
the price to `20` can be represented as removing that row and adding `(id=7,
price=20)` in one atomic commit.
- Comparing the added row against the entire parent snapshot finds the old
id=7 and incorrectly reports a duplicate.
- Comparing it against the parent rows that survive the commit finds no
collision because the old row is being removed.
A more precise spec wording could be:
> On retry, writers must verify that added rows have distinct keys among
themselves and do not conflict with rows remaining from the new parent after
applying the commit’s removals.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]