db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "ASF subversion and git services (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (DERBY-3330) provide support for unique constraint over keys that include one or more nullable columns.
Date Mon, 25 Nov 2013 20:31:38 GMT

    [ https://issues.apache.org/jira/browse/DERBY-3330?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13831879#comment-13831879

ASF subversion and git services commented on DERBY-3330:

Commit 1545394 from [~dagw] in branch 'code/trunk'
[ https://svn.apache.org/r1545394 ]

DERBY-532 Support deferrable constraints

Patch derby-532-post-scan-4 implements basic support for deferred
constraints for PRIMARY KEY and UNIQUE constraints. Deferrable
constraints are not enabled by default yet; one needs to set a
property to try the feature: "derby.constraintsTesting".

This patch enables deferred constraints for:

    a) primary key constraints
    b) unique constraint with not nullable columns
    c) unique constraint with nullable columns

by new logic in insertion and sorts.

The patch includes relaxing the constraint at insertion and update
time, as well as adding a constraint to an existing table. 

Derby treats constraints a) and b) the same, and in the code these are
marked as "unique" when they are not deferrable (as in existing code).

Constraint type c) is currently marked as
"uniqueWithDuplicateNulls". Insert/update of these is implemented in
the BTree by including the RowLocation of the base row in the set of
keys in the index row (DERBY-3330). This makes them trivially unique,
but there is an extra code path in BTreeController that checks
neighbor rows for duplicates, and only allows insertion if the key
contains a null. When adding a constraint to an existing table, these
are handled by a specially crafted sorter

The implementation of insert/update of deferrable indexes is based on
a similar approach, i.e. by backing with a non-unique index, and checking 
duplicates in the language layer, notably IndexChanger.

In IndexChanger, after inserting a row, we check if it is unique by
performing a scan of the BTree. A time-out here leads to a pessimistic
assumption that there is a duplicate. Duplicate key values are saved
until checking time (usually commit time), when a new scan is
performed to validate the uniqueness property.

[This means a) and b) if deferrable are no longer marked "unique"].

Deferrable indexes are not shared.

If there are duplicates and we have deferred constraint mode (a
dynamic session property), we save the duplicate index row in a disk
based hash table (DeferredDuplicates#rememberDuplicate).

For a) and b), constraints which are deferrable are marked as
"uniqueDeferrable" and "hasDeferrableChecking". Constraints of type c)
which are deferrable are marked "uniqueWithDuplicateNulls" and
"hasDeferrableChecking". These marks determines the code paths
used. Note that existing indexes and non-deferrable constraint do not
get a new code path, which should preserve correctness and performance
of those.

Now, with these markers in place, deferral of checks happens in three

    {{ IndexChanger#insertAndCheckDups}}

    {{CreateIndexConstantAction#executeConstantAction +
     MergeSort#compare and UniqueWithDuplicateNullsMergeSort#compare }}


The former is active for deferral under INSERT and UPDATE. The middle
when adding a deferrable constraint to an existing table, when we sort
existing rows detecting any duplicates. The last is used when importing

At transaction commit (1), or when the constraint mode for a deferred
constraint is changed back to immediate (2), we validate the
constraint (DeferredDuplicates#validate) by replaying the hash table
and scanning the index for the duplicate index rows to ascertain there
are none, or else we have an error: transaction or statement severity
respectively for (1) and (2).

The constraint mode is a SQL session level variable, and inside
routines (nested connections), we push this on the stack. This means
change of the constraint mode inside nested connections will be popped
on routine exit. If, as part of this, a constraint changes from
deferred to immediate mode, we also validate it for correctness. If
this fail, the transaction rolls back
We needed to do this from a newly introduced method,
GenericLanguageConnectionContext#popNestedSessionContext. This
pops the SQL session context.
That hook is called from GenericPreparedStatement#executeStmt. As a
part of this effort, we also renamed #setupNestedSessionContext to

The patch also adds support for checking deferred constraints in
xa_prepare and xa_commit (.., true), cf. specification attached to the
JIRA issue.

Concurrency: if a transaction gets a lock time-out when trying to
establish if a row just inserted is a duplicate (another transaction
may have just inserted a row with a similar index key), we use a
pessimistics assumption and add that key to the set of keys to be
checked at commit time. If a key can't be grabbed then, a time-out is
thrown. We plan to add an optimized scan to avoid waiting for the lock
at insertion time, cf DERBY-6419.

The "not enforced" feature is not yet implemented in this patch.

Several new test cases been added to ConstraintCharacteristicsTest to
test these basic behaviors.

> provide support for unique constraint over keys that include one or more nullable columns.
> ------------------------------------------------------------------------------------------
>                 Key: DERBY-3330
>                 URL: https://issues.apache.org/jira/browse/DERBY-3330
>             Project: Derby
>          Issue Type: Improvement
>          Components: SQL, Store
>    Affects Versions:
>         Environment: all
>            Reporter: Anurag Shekhar
>            Assignee: Anurag Shekhar
>             Fix For:
>         Attachments: BTreeController.diff, FunctionalSpec_DERBY-3330-V2.html, FunctionalSpec_DERBY-3330.html,
UniqueConstraint_Implementation.html, UniqueConstraint_Implementation_V2.html, UniqueConstraint_Implementation_V3.html,
UniqueConstraint_Implementation_V4.html, db2Compatibility-v2.diff, db2Compatibility.diff,
derby-3330-UpgradeTests.diff, derby-3330-testcase.diff, derby-3330.diff, derby-3330_followup_1.diff,
derby-3330_followup_1_modified.diff, derby-3330v10.diff, derby-3330v11.diff, derby-3330v12.diff,
derby-3330v13.diff, derby-3330v2.diff, derby-3330v3.diff, derby-3330v4.diff, derby-3330v5.diff,
derby-3330v6.diff, derby-3330v7.diff, derby-3330v8.diff, derby-3330v9.diff, derbyall_report.txt,
> Allow unique constraint over keys which include one or more nullable fields.  Prior to
this change Derby only supported unique constraints on keys that included no nullable columns.
 The new constraint will allow unlimited inserts of any key with one more null columns, but
will limit insert of keys with no null columns to 1 unique value per table.
> There is no change to existing or newly created unique indexes on null columns (as opposed
to unique constraints on null columns).  Also there is no change to existing or newly created
constraints on keys with no nullable columns.

This message was sent by Atlassian JIRA

View raw message