Re: toTimestamp fractional seconds fix (patch against CVS)

Поиск
Список
Период
Сортировка
От Barry Lind
Тема Re: toTimestamp fractional seconds fix (patch against CVS)
Дата
Msg-id 3E07B6CD.3070405@xythos.com
обсуждение исходный текст
Ответ на toTimestamp fractional seconds fix (patch against CVS)  (Florian Wunderlich <fwunderlich@devbrain.de>)
Список pgsql-jdbc
Florian,

I would request that you also include an update to the jdbc test suite
that tests for the case you are fixing.  Other than that, the patch
looks fine.  When you resubmit with the updated tests I will apply.

thanks,
--Barry


Florian Wunderlich wrote:
> In the CVS, in AbstractJdbc1ResultSet.java, a Timestamp returned from
> toTimestamp is created with DateFormat.parse, which means that
> fractional milliseconds are dropped - no more than 3 fractional digits
> are considered.
>
> 1. This means that the JDBC driver returns values that are not in the
> database. A subsequent query specifying this value in a WHERE clause for
> example will not return the record in question.
>
> 2. java.sql.Timestamp specifies that all fractional seconds are to be
> stored in the nanos field, and that the getTime method shall return only
> integral seconds.
>
> The attached patch against the most recent version from the CVS as of
> 2002-12-23 14:02 (rev 1.7) fixes this behavior. I have verified it
> against postgresql-7.2.1.
>
>
> ------------------------------------------------------------------------
>
> Index: AbstractJdbc1ResultSet.java
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java,v
> retrieving revision 1.7
> diff -u -b -r1.7 AbstractJdbc1ResultSet.java
> --- AbstractJdbc1ResultSet.java    2002/10/19 22:10:36    1.7
> +++ AbstractJdbc1ResultSet.java    2002/12/23 12:49:34
> @@ -844,8 +844,15 @@
>      * Java also expects fractional seconds to 3 places where postgres
>      * will give, none, 2 or 6 depending on the time and postgres version.
>      * From version 7.2 postgres returns fractional seconds to 6 places.
> -    * If available, we drop the last 3 digits.
>      *
> +        * According to the Timestamp documentation, fractional digits are kept
> +        * in the nanos field of Timestamp and not in the milliseconds of Date.
> +        * Thus, parsing for fractional digits is entirely separated from the
> +        * rest.
> +        *
> +        * The method assumes that there are no more than 9 fractional
> +        * digits given. Undefined behavior if this is not the case.
> +    *
>      * @param s           The ISO formated date string to parse.
>      * @param resultSet The ResultSet this date is part of.
>      *
> @@ -881,6 +888,18 @@
>              rs.sbuf.append(s);
>              int slen = s.length();
>
> +
> +                        //
> +                        // For a Timestamp, the fractional seconds are stored in the
> +                        // nanos field. As a DateFormat is used for parsing which can
> +                        // only parse to millisecond precision and which returns a
> +                        // Date object, the fractional second parsing is completely
> +                        // separate.
> +                        //
> +
> +                        int nanos = 0;
> +
> +
>              if (slen > 19)
>              {
>                  // The len of the ISO string to the second value is 19 chars. If
> @@ -894,25 +913,42 @@
>                  char c = s.charAt(i++);
>                  if (c == '.')
>                  {
> -                    // Found a fractional value. Append up to 3 digits including
> -                    // the leading '.'
> +                                        // Found a fractional value.
> +
> +                                        final int start = i;
> +
>                      do
>                      {
> -                        if (i < 24)
> -                            rs.sbuf.append(c);
>                          c = s.charAt(i++);
>                      }
>                      while (i < slen && Character.isDigit(c));
> +
> +
> +                                        //
> +                                        // The range [start, i - 1) contains all fractional digits.
> +                                        //
> +
> +                                        final int end = i - 1;
>
> -                    // If there wasn't at least 3 digits we should add some zeros
> -                    // to make up the 3 digits we tell java to expect.
> -                    for (int j = i; j < 24; j++)
> -                        rs.sbuf.append('0');
> +                                        try
> +                                        {
> +                                          nanos = Integer.parseInt(s.substring(start, end));
>                  }
> -                else
> +                                        catch (NumberFormatException e)
>                  {
> -                    // No fractional seconds, lets add some.
> -                    rs.sbuf.append(".000");
> +                                          // this Exception can never happen, as the range has
> +                                          // been checked before.
> +                                        }
> +
> +
> +                                        //
> +                                        // The nanos field stores nanoseconds. Adjust the parsed
> +                                        // value to the correct magnitude.
> +                                        //
> +
> +                                        for (int digitsToNano = 9 - (end - start);
> +                                             digitsToNano > 0; --digitsToNano)
> +                                          nanos *= 10;
>                  }
>
>                  if (i < slen)
> @@ -929,7 +965,7 @@
>                          rs.sbuf.append(":00");
>
>                      // we'll use this dateformat string to parse the result.
> -                    df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
> +                    df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
>                  }
>                  else
>                  {
> @@ -938,11 +974,11 @@
>                      if (pgDataType.equals("timestamptz"))
>                      {
>                          rs.sbuf.append(" GMT");
> -                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
> +                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
>                      }
>                      else
>                      {
> -                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
> +                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
>                      }
>                  }
>              }
> @@ -982,8 +1018,13 @@
>                  // All that's left is to parse the string and return the ts.
>                  if ( org.postgresql.Driver.logDebug )
>                      org.postgresql.Driver.debug( "" + df.parse(rs.sbuf.toString()).getTime() );
> +
> +                                final Timestamp result =
> +                                  new Timestamp(df.parse(rs.sbuf.toString()).getTime());
> +
> +                                result.setNanos(nanos);
>
> -                return new Timestamp(df.parse(rs.sbuf.toString()).getTime());
> +                                return result;
>              }
>              catch (ParseException e)
>              {
>
>
> ------------------------------------------------------------------------
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
> subscribe-nomail command to majordomo@postgresql.org so that your
> message can get through to the mailing list cleanly




В списке pgsql-jdbc по дате отправления:

Предыдущее
От: Dave Cramer
Дата:
Сообщение: Re: Using 7.1 driver with 7.3?
Следующее
От: Barry Lind
Дата:
Сообщение: Re: Again: Patch against 7.3.1 AbstractJdbc1Connection.java