Skip to Content.
Sympa Menu

freetds - Patch to work around JVM optimization bug

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: Bob Kline <bkline AT rksystems.com>
  • To: Craig Spannring <freetds-jdbc-bugs AT internetcds.com>, TDS Development Group <freetds AT franklin.oit.unc.edu>
  • Cc: Julien de Murcia <demurcia AT sablet.grenoble.hp.com>
  • Subject: Patch to work around JVM optimization bug
  • Date: Mon, 14 Aug 2000 09:06:40 -0400 (EDT)

The problem which was reported last week with randomly incorrect dates
being returned from queries turned out to have been caused by a bug in
the Java virtual machine's optimization (specifically version 1.2.2,
Java HotSpot Server VM 2.0fcs, mixed code, build E), which wasn't
handling complex mathematical expressions properly in all cases. The
attached file contains a patch which simplifies the calculations used
when parsing dates returned in the TDS buffer, breaking down the
formulas into smaller incremental steps using more temporary variables
to reduce the chances for the optimizer to get confused. It also does
some promotions to long int sooner to ensure that the code will work
with dates well into the future.

This has been run through the unittests suite, and has also been tested
by the list member posting the original problem, who reports that with
the patch the problem no longer occurs. Please fold this into the
latest snapshot. Please also fix unittests/Makefile so that t0006 uses
the same type of rule as all the other tests, and unittests/t0036 so
that it does not fail if the tables being dropped do not already exist.

Thanks.

--
Bob Kline
mailto:bkline AT rksystems.com
http://www.rksystems.com


diff -Naur original/Tds.java modified/Tds.java
--- original/Tds.java Mon Jul 17 00:41:06 2000
+++ modified/Tds.java Fri Aug 11 15:41:50 2000
@@ -1848,6 +1848,10 @@
int type)
throws java.io.IOException, TdsException
{
+ // Some useful constants
+ final long SECONDS_PER_DAY = 24L * 60L * 60L;
+ final long DAYS_BETWEEN_1900_AND_1970 = 25567L;
+
int len;
Object result;

@@ -1877,14 +1881,19 @@
// It appears that a datetime is made of of 2 32bit ints
// The first one is the number of days since 1900
// The second integer is the number of seconds*300
- int days = comm.getTdsInt();
- int time = comm.getTdsInt();
- long seconds = (long)((days - 25567)*(24*60*60))
- + (long)(time/300);
- long micros = ((time % 300) * 1000000) / 300;
- long millis = (micros / 1000)
- + ((micros % 1000)>=500 ? 1 : 0)
- + seconds * 1000 - zoneOffset;
+ // The reason the calculations below are sliced up into
+ // such small baby steps is to avoid a bug in JDK1.2.2's
+ // runtime, which got confused by the original complexity.
+ long tdsDays = (long)comm.getTdsInt();
+ long tdsTime = (long)comm.getTdsInt();
+ long sqlDays = tdsDays - DAYS_BETWEEN_1900_AND_1970;
+ long seconds = sqlDays * SECONDS_PER_DAY + tdsTime / 300L;
+ long micros = ((tdsTime % 300L) * 1000000L) / 300L;
+ long millis = seconds * 1000L + micros / 1000L - zoneOffset;
+
+ // Round up if appropriate.
+ if (micros % 1000L >= 500L)
+ millis++;

result = new Timestamp(millis - getDstOffset(millis));
break;
@@ -1897,11 +1906,11 @@
// the second smallint is the number of minutes past
// midnight.

- int days = comm.getTdsShort();
- int minutes = comm.getTdsShort();
- long seconds = (long)((days - 25567)*(24*60*60))
- + (long)(minutes * 60);
- long millis = seconds * 1000 - zoneOffset;
+ long tdsDays = (long)comm.getTdsShort();
+ long minutes = (long)comm.getTdsShort();
+ long sqlDays = tdsDays - DAYS_BETWEEN_1900_AND_1970;
+ long seconds = sqlDays * SECONDS_PER_DAY + minutes * 60L;
+ long millis = seconds * 1000L - zoneOffset;

result = new Timestamp(millis - getDstOffset(millis));
break;


  • Patch to work around JVM optimization bug, Bob Kline, 08/14/2000

Archive powered by MHonArc 2.6.24.

Top of Page