Fixed #24959 -- Fixed queries using negative timedeltas on MySQL and Oracle.

This commit is contained in:
Mariusz Felisiak 2016-11-23 15:10:47 +01:00 committed by Tim Graham
parent 2742901ac2
commit b63d0c54b0
3 changed files with 23 additions and 11 deletions

View File

@ -94,8 +94,7 @@ class DatabaseOperations(BaseDatabaseOperations):
return "TIME(%s)" % (field_name) return "TIME(%s)" % (field_name)
def date_interval_sql(self, timedelta): def date_interval_sql(self, timedelta):
return "INTERVAL '%d 0:0:%d:%d' DAY_MICROSECOND" % ( return "INTERVAL '%06f' SECOND_MICROSECOND" % (timedelta.total_seconds()), []
timedelta.days, timedelta.seconds, timedelta.microseconds), []
def format_for_duration_arithmetic(self, sql): def format_for_duration_arithmetic(self, sql):
if self.connection.features.supports_microsecond_precision: if self.connection.features.supports_microsecond_precision:

View File

@ -93,16 +93,9 @@ WHEN (new.%(col_name)s IS NULL)
def date_interval_sql(self, timedelta): def date_interval_sql(self, timedelta):
""" """
Implements the interval functionality for expressions NUMTODSINTERVAL converts number to INTERVAL DAY TO SECOND literal.
format for Oracle:
INTERVAL '3 00:03:20.000000' DAY(1) TO SECOND(6)
""" """
minutes, seconds = divmod(timedelta.seconds, 60) return "NUMTODSINTERVAL(%06f, 'SECOND')" % (timedelta.total_seconds()), []
hours, minutes = divmod(minutes, 60)
days = str(timedelta.days)
day_precision = len(days)
fmt = "INTERVAL '%s %02d:%02d:%02d.%06d' DAY(%d) TO SECOND(6)"
return fmt % (days, hours, minutes, seconds, timedelta.microseconds, day_precision), []
def date_trunc_sql(self, lookup_type, field_name): def date_trunc_sql(self, lookup_type, field_name):
# http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm#i1002084 # http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm#i1002084

View File

@ -1043,6 +1043,26 @@ class FTimeDeltaTests(TestCase):
).order_by('name') ).order_by('name')
self.assertQuerysetEqual(over_estimate, ['e3', 'e4'], lambda e: e.name) self.assertQuerysetEqual(over_estimate, ['e3', 'e4'], lambda e: e.name)
def test_negative_timedelta_update(self):
# subtract 30 seconds, 30 minutes, 2 hours and 2 days
experiments = Experiment.objects.filter(name='e0').annotate(
start_sub_seconds=F('start') + datetime.timedelta(seconds=-30),
).annotate(
start_sub_minutes=F('start_sub_seconds') + datetime.timedelta(minutes=-30),
).annotate(
start_sub_hours=F('start_sub_minutes') + datetime.timedelta(hours=-2),
).annotate(
new_start=F('start_sub_hours') + datetime.timedelta(days=-2),
)
expected_start = datetime.datetime(2010, 6, 23, 9, 45, 0)
if connection.features.supports_microsecond_precision:
# subtract 30 microseconds
experiments = experiments.annotate(new_start=F('new_start') + datetime.timedelta(microseconds=-30))
expected_start += datetime.timedelta(microseconds=+746970)
experiments.update(start=F('new_start'))
e0 = Experiment.objects.get(name='e0')
self.assertEqual(e0.start, expected_start)
class ValueTests(TestCase): class ValueTests(TestCase):
def test_update_TimeField_using_Value(self): def test_update_TimeField_using_Value(self):