db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Knut Anders Hatlen (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (DERBY-5866) testFiringConstraintOrder(org.apache.derbyTesting.functionTests.tests.lang.TriggerTest)junit.framework.AssertionFailedError: matching triggers need to be fired in order creation:1,NO CASCADE BEFORE,DELETE,ROW
Date Fri, 20 Dec 2013 12:52:15 GMT

     [ https://issues.apache.org/jira/browse/DERBY-5866?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Knut Anders Hatlen updated DERBY-5866:
--------------------------------------

    Issue & fix info: High Value Fix  (was: High Value Fix,Patch Available)

I'm not quite happy with the approach in the patch, so I'm removing the Patch Available flag
until I've explored some more options.

In particular, the code that checks if the current timestamp is higher than the timestamp
of the most recent trigger, may be unreliable. I haven't been able to construct a case where
it breaks, but I think it relies on some unspecified behaviour in java.util.Calendar and is
not guaranteed to give the correct result.

For example: When the local timezone switches from DST to standard time, there is a two-hour
period where a timestamp without timezone (which is how it is stored in a Derby TIMESTAMP
column) is ambiguous. That is, if the switch happens at 03:00 DST -> 02:00 std, a TIMESTAMP
stored as 02:30 in the database could represent either 02:30 DST or 02:30 std (an hour later).

If, say, one trigger is created at 02:45 DST, and another one is created half an hour later,
at 02:15 std, here's what the code in the patch does when the second trigger is created:

1) Create a java.sql.Timestamp representing the current time (02:15 std), let's call it tsNew.

2) Fetch the creation timestamp (as a java.sql.Timestamp) for the TriggerDescriptor of the
first trigger. This timestamp is 02:45, but since the timezone is not stored in the database,
it is unknown whether it's DST or std. Let's call it tsOld.

3) Check if tsOld < tsNew
3a) If tsOld is DST, (tsOld < tsNew) is true, and we use tsNew as creation timestamp. It
will be stored as 02:15 in the database.
3b) If tsOld is std, (tsOld < tsNew) is false, and we use tsOld + 1ms as creation timestamp.
It will be stored as 02:45:00.001 in the database.

Now, if 3a happens, we will end up with the first trigger having creation timestamp 02:45
and the second trigger having creation timestamp 02:15. That will lead to wrong execution
order, so we don't want that to happen.

What actually happens here, at least in all test cases I've managed to construct, is 3b. That
is, the first trigger has timestamp 02:45 and the second has 02:45:00.001. This gives the
correct execution order. (However, the creation timestamp of the second trigger lies with
half an hour to achieve this.)

But 3b is only guaranteed if we know that getTimestamp() on an ambiguous timestamp will always
return the highest alternative. That is, if we know that the returned java.sql.Timestamp value
for the ambiguous column value 02:15 above will always be 02:15 std and not 02:15 DST, we're
fine. I'm not able to find anything in the API specification that guarantees this, though.
I did find a comment buried in OpenJDK's implementation of java.util.GregorianCalendar that
suggests standard time will be used in case of ambiguities, but nothing in the actual API
reference. So it might be that the current approach works in all cases, but even so it seems
like it depends on an internal implementation detail in the Java class libraries.

I'm thinking that one possible fix that should make this code more reliable, is to store the
trigger creation timestamp in UTC instead of the local timezone. Then we'd avoid the DST problems,
as well as the problems with the database being moved from one timezone to another. An additional
benefit is that we wouldn't have to lie when creating the timestamp around the DST switch
(such as adjusting the timestamp with half an hour in the 3b scenario described above).

>  testFiringConstraintOrder(org.apache.derbyTesting.functionTests.tests.lang.TriggerTest)junit.framework.AssertionFailedError:
matching triggers need to be fired in order creation:1,NO CASCADE BEFORE,DELETE,ROW
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: DERBY-5866
>                 URL: https://issues.apache.org/jira/browse/DERBY-5866
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 10.10.1.1, 10.10.1.3
>         Environment: Windows IBM 1.6 10.10.0.0 alpha - (1361856)
>            Reporter: Kathey Marsden
>            Assignee: Knut Anders Hatlen
>              Labels: derby_triage10_11
>         Attachments: d5866-1a-adjust-timestamp.diff, error-stacktrace.out, fail1.zip,
fail2.zip, time-zone-test.diff
>
>
> I saw this failure in the IBM nightlies on 7/15. The subsequent night did not fail, so
appears intermittent
> http://cloudsoft.usca.ibm.com/intranet/nightlies/derbywinvm/JarResults.2012-07-15/ibm16_suites.All/suites.All.out
> 1) testFiringConstraintOrder(org.apache.derbyTesting.functionTests.tests.lang.TriggerTest)junit.framework.AssertionFailedError:
matching triggers need to be fired in order creation:1,NO CASCADE BEFORE,DELETE,ROW
> 	at org.apache.derbyTesting.functionTests.tests.lang.TriggerTest.assertFiringOrder(TriggerTest.java:560)
> 	at org.apache.derbyTesting.functionTests.tests.lang.TriggerTest.testFiringConstraintOrder(TriggerTest.java:500)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
> 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
> 	at org.apache.derbyTesting.junit.BaseTestCase.runBare(BaseTestCase.java:117)
> 	at org.apache.derbyTesting.junit.BaseJDBCTestCase.runBareOverridable(BaseJDBCTestCase.java:424)
> 	at org.apache.derbyTesting.junit.BaseJDBCTestCase.runBare(BaseJDBCTestCase.java:441)
> 	at junit.extensions.TestDecorator.basicRun(TestDecorator.java:24)
> 	at junit.extensions.TestSetup$1.protect(TestSetup.java:21)
> 	at junit.extensions.TestSetup.run(TestSetup.java:25)
> 	at org.apache.derbyTesting.junit.BaseTestSetup.run(BaseTestSetup.java:57)



--
This message was sent by Atlassian JIRA
(v6.1.4#6159)

Mime
View raw message