[ruby-oci8-commit] [452] trunk/ruby-oci8: add OCI8::BindType::OCITimestamp, OCI8::BindType:: LocalDateTime,

nobody at rubyforge.org nobody at rubyforge.org
Sun Oct 9 09:26:28 EDT 2011


Revision: 452
Author:   kubo
Date:     2011-10-09 09:26:27 -0400 (Sun, 09 Oct 2011)

Log Message:
-----------
add OCI8::BindType::OCITimestamp, OCI8::BindType::LocalDateTime,
OCI8::BindType::UTCDateTime, OCI8::BindType::LocalTime and
OCI8::BindType::UTCTime.  The first is used for internal use. The
others are used for timestamp (without time zone) datatype.

Modified Paths:
--------------
    trunk/ruby-oci8/ChangeLog
    trunk/ruby-oci8/ext/oci8/ocidatetime.c
    trunk/ruby-oci8/lib/oci8/datetime.rb
    trunk/ruby-oci8/lib/oci8/object.rb

Modified: trunk/ruby-oci8/ChangeLog
===================================================================
--- trunk/ruby-oci8/ChangeLog	2011-10-01 04:20:02 UTC (rev 451)
+++ trunk/ruby-oci8/ChangeLog	2011-10-09 13:26:27 UTC (rev 452)
@@ -1,3 +1,10 @@
+2011-10-09  KUBO Takehiro  <kubo at jiubao.org>
+	* ext/oci8/ocidatetime.c, lib/oci8/datetime.rb, lib/oci8/object.rb:
+	    add OCI8::BindType::OCITimestamp, OCI8::BindType::LocalDateTime,
+	    OCI8::BindType::UTCDateTime, OCI8::BindType::LocalTime and
+	    OCI8::BindType::UTCTime. The first is used for internal use.
+	    The others are used for timestamp (without time zone) datatype.
+
 2011-10-01  KUBO Takehiro  <kubo at jiubao.org>
 	* ext/oci8/attr.c, ext/oci8/ocidatetime.c, ext/oci8/oradate.c: delete
 	    subversion keywords.

Modified: trunk/ruby-oci8/ext/oci8/ocidatetime.c
===================================================================
--- trunk/ruby-oci8/ext/oci8/ocidatetime.c	2011-10-01 04:20:02 UTC (rev 451)
+++ trunk/ruby-oci8/ext/oci8/ocidatetime.c	2011-10-09 13:26:27 UTC (rev 452)
@@ -2,7 +2,7 @@
 /*
  *  ocidatetime.c
  *
- * Copyright (C) 2005-2008 KUBO Takehiro <kubo at jiubao.org>
+ * Copyright (C) 2005-2011 KUBO Takehiro <kubo at jiubao.org>
  *
  */
 #include "oci8.h"
@@ -65,6 +65,12 @@
     return od;
 }
 
+static void bind_init_common(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
+{
+    obind->value_sz = sizeof(void *);
+    obind->alloc_sz = sizeof(void *);
+}
+
 static void bind_init_elem_common(oci8_bind_t *obind, VALUE svc, ub4 type)
 {
     ub4 idx = 0;
@@ -95,7 +101,7 @@
     oci8_bind_free(base);
 }
 
-VALUE oci8_make_ocitimestamp_tz(OCIDateTime *dttm)
+VALUE oci8_make_ocitimestamp(OCIDateTime *dttm, boolean have_tz)
 {
     sb2 year;
     ub1 month;
@@ -106,13 +112,12 @@
     ub4 fsec;
     sb1 tz_hour;
     sb1 tz_minute;
-    sword rv;
-    int have_tz;
 
     oci_lc(OCIDateTimeGetDate(oci8_envhp, oci8_errhp, dttm, &year, &month, &day));
     oci_lc(OCIDateTimeGetTime(oci8_envhp, oci8_errhp, dttm, &hour, &minute, &sec, &fsec));
-    rv = OCIDateTimeGetTimeZoneOffset(oci8_envhp, oci8_errhp, dttm, &tz_hour, &tz_minute);
-    have_tz = (rv == OCI_SUCCESS);
+    if (have_tz) {
+        oci_lc(OCIDateTimeGetTimeZoneOffset(oci8_envhp, oci8_errhp, dttm, &tz_hour, &tz_minute));
+    }
     return rb_ary_new3(9,
                        INT2FIX(year),
                        INT2FIX(month),
@@ -207,9 +212,43 @@
     return dttm;
 }
 
+static VALUE bind_ocitimestamp_get(oci8_bind_t *obind, void *data, void *null_struct)
+{
+    return oci8_make_ocitimestamp(*(OCIDateTime **)data, FALSE);
+}
+
+static void bind_ocitimestamp_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
+{
+    oci8_set_ocitimestamp_tz(*(OCIDateTime **)data, val, Qnil);
+}
+
+static void bind_ocitimestamp_init_elem(oci8_bind_t *obind, VALUE svc)
+{
+    bind_init_elem_common(obind, svc, OCI_DTYPE_TIMESTAMP);
+}
+
+static void bind_ocitimestamp_free(oci8_base_t *base)
+{
+    bind_free_common(base, OCI_DTYPE_TIMESTAMP);
+}
+
+static const oci8_bind_vtable_t bind_ocitimestamp_vtable = {
+    {
+        NULL,
+        bind_ocitimestamp_free,
+        sizeof(oci8_bind_t)
+    },
+    bind_ocitimestamp_get,
+    bind_ocitimestamp_set,
+    bind_init_common,
+    bind_ocitimestamp_init_elem,
+    NULL,
+    SQLT_TIMESTAMP
+};
+
 static VALUE bind_ocitimestamp_tz_get(oci8_bind_t *obind, void *data, void *null_struct)
 {
-    return oci8_make_ocitimestamp_tz(*(OCIDateTime **)data);
+    return oci8_make_ocitimestamp(*(OCIDateTime **)data, TRUE);
 }
 
 static void bind_ocitimestamp_tz_set(oci8_bind_t *obind, void *data, void **null_structp, VALUE val)
@@ -378,12 +417,6 @@
     oci8_set_ociinterval_ym(*(OCIInterval **)data, val);
 }
 
-static void bind_ociinterval_ym_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
-{
-    obind->value_sz = sizeof(OCIInterval*);
-    obind->alloc_sz = sizeof(OCIInterval*);
-}
-
 static void bind_ociinterval_ym_init_elem(oci8_bind_t *obind, VALUE svc)
 {
     bind_init_elem_common(obind, svc, OCI_DTYPE_INTERVAL_YM);
@@ -404,12 +437,6 @@
     oci8_set_ociinterval_ds(*(OCIInterval **)data, val);
 }
 
-static void bind_ociinterval_ds_init(oci8_bind_t *obind, VALUE svc, VALUE val, VALUE length)
-{
-    obind->value_sz = sizeof(OCIInterval *);
-    obind->alloc_sz = sizeof(OCIInterval *);
-}
-
 static void bind_ociinterval_ds_init_elem(oci8_bind_t *obind, VALUE svc)
 {
     bind_init_elem_common(obind, svc, OCI_DTYPE_INTERVAL_DS);
@@ -428,7 +455,7 @@
     },
     bind_ociinterval_ym_get,
     bind_ociinterval_ym_set,
-    bind_ociinterval_ym_init,
+    bind_init_common,
     bind_ociinterval_ym_init_elem,
     NULL,
     SQLT_INTERVAL_YM
@@ -442,7 +469,7 @@
     },
     bind_ociinterval_ds_get,
     bind_ociinterval_ds_set,
-    bind_ociinterval_ds_init,
+    bind_init_common,
     bind_ociinterval_ds_init_elem,
     NULL,
     SQLT_INTERVAL_DS
@@ -450,6 +477,7 @@
 
 void Init_oci_datetime(void)
 {
+    oci8_define_bind_class("OCITimestamp", &bind_ocitimestamp_vtable);
     oci8_define_bind_class("OCITimestampTZ", &bind_ocitimestamp_tz_vtable);
     oci8_define_bind_class("OCIIntervalYM", &bind_ociinterval_ym_vtable);
     oci8_define_bind_class("OCIIntervalDS", &bind_ociinterval_ds_vtable);

Modified: trunk/ruby-oci8/lib/oci8/datetime.rb
===================================================================
--- trunk/ruby-oci8/lib/oci8/datetime.rb	2011-10-01 04:20:02 UTC (rev 451)
+++ trunk/ruby-oci8/lib/oci8/datetime.rb	2011-10-09 13:26:27 UTC (rev 452)
@@ -59,7 +59,7 @@
 
       private
 
-      def datetime_to_array(val, full)
+      def datetime_to_array(val, datatype)
         return nil if val.nil?
 
         # year
@@ -98,7 +98,7 @@
         else
           sec = 0
         end
-        return [year, month, day, hour, minute, sec] unless full
+        return [year, month, day, hour, minute, sec] if datatype == :date
 
         # fractional second
         if val.respond_to? :sec_fraction
@@ -110,6 +110,8 @@
         else
           fsec = 0
         end
+        return [year, month, day, hour, minute, sec, fsec, nil, nil] if datatype == :timestamp
+
         # time zone
         if val.respond_to? :offset
           # DateTime
@@ -134,55 +136,40 @@
         [year, month, day, hour, minute, sec, fsec, tz_hour, tz_min]
       end
 
-      def ocidate_to_datetime(ary)
+      def array_to_datetime(ary, timezone)
         return nil if ary.nil?
 
-        year, month, day, hour, minute, sec = ary
-        if @@default_timezone == :local
-          if ::DateTime.respond_to? :local_offset
-            offset = ::DateTime.local_offset # Use a method defined by active support.
+        year, month, day, hour, minute, sec, nsec, tz_hour, tz_min = ary
+        sec += nsec.to_r / 1000000000 if nsec and nsec != 0
+        if tz_hour and tz_min
+          offset = tz_hour.to_r / 24 + tz_min.to_r / 1440
+        else
+          if @@default_timezone == :local
+            if ::DateTime.respond_to? :local_offset
+              offset = ::DateTime.local_offset # Use a method defined by active support.
+            else
+              # Do as active support does.
+              offset = ::Time.local(2007).utc_offset.to_r / 86400
+            end
           else
-            # Do as active support does.
-            offset = ::Time.local(2007).utc_offset.to_r / 86400
+            offset = 0
           end
-        else
-          offset = 0
         end
-        ::DateTime.civil(year, month, day, hour, minute, sec, offset)
-      end
 
-      def ocidate_to_time(ary)
-        return nil if ary.nil?
-
-        year, month, day, hour, minute, sec = ary
-        if @@time_new_accepts_timezone || year >= 139 || year < 0
-          begin
-            return ::Time.send(@@default_timezone, year, month, day, hour, minute, sec)
-          rescue StandardError
-          end
-        end
-        ocidate_to_datetime(ary)
-      end
-
-      def ocitimestamp_to_datetime(ary)
-        return nil if ary.nil?
-
-        year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
-        if @@datetime_has_fractional_second_bug and sec >= 59 and fsec != 0
+        if @@datetime_has_fractional_second_bug and sec >= 59 and nsec != 0
           # convert to a DateTime via a String as a workaround
-          if tz_hour >= 0 && tz_min >= 0
+          if offset >= 0
             sign = ?+
           else
             sign = ?-
-            tz_hour = - tz_hour
-            tz_min = - tz_min
+            offset = - offset;
           end
+          tz_min = (offset * 1440).to_i
+          tz_hour, tz_min = tz_min.divmod 60
           time_str = format("%04d-%02d-%02dT%02d:%02d:%02d.%09d%c%02d:%02d",
-                            year, month, day, hour, minute, sec, fsec, sign, tz_hour, tz_min)
+                            year, month, day, hour, minute, sec, nsec, sign, tz_hour, tz_min)
           ::DateTime.parse(time_str)
         else
-          sec += fsec.to_r / 1000000000
-          offset = tz_hour.to_r / 24 + tz_min.to_r / 1440
           ::DateTime.civil(year, month, day, hour, minute, sec, offset)
         end
       end
@@ -190,36 +177,48 @@
       if @@time_new_accepts_timezone
 
         # after ruby 1.9.2
-        def ocitimestamp_to_time(ary)
+        def array_to_time(ary, timezone)
           return nil if ary.nil?
 
-          year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
+          year, month, day, hour, minute, sec, nsec, tz_hour, tz_min = ary
+          nsec ||= 0
 
-          sec += fsec / Rational(1000000000)
-          utc_offset = tz_hour * 3600 + tz_min * 60
-          return ::Time.new(year, month, day, hour, minute, sec, utc_offset)
+          if timezone
+            usec = (nsec == 0) ? 0 : nsec.to_r / 1000
+            ::Time.send(timezone, year, month, day, hour, minute, sec, usec)
+          else
+            sec += nsec.to_r / 1_000_000_000 if nsec != 0
+            utc_offset = tz_hour * 3600 + tz_min * 60
+            ::Time.new(year, month, day, hour, minute, sec, utc_offset)
+          end
         end
 
       else
 
         # prior to ruby 1.9.2
-        def ocitimestamp_to_time(ary)
+        def array_to_time(ary, timezone)
           return nil if ary.nil?
 
-          year, month, day, hour, minute, sec, fsec, tz_hour, tz_min = ary
-
-          if year >= 139 || year < 0
-            begin
+          year, month, day, hour, minute, sec, nsec, tz_hour, tz_min = ary
+          nsec ||= 0
+          usec = (nsec == 0) ? 0 : nsec.to_r / 1000
+          begin
+            if timezone
+              return ::Time.send(:timezone, year, month, day, hour, minute, sec, usec)
+            else
               if tz_hour == 0 and tz_min == 0
-                return ::Time.utc(year, month, day, hour, minute, sec, fsec / Rational(1000))
+                tm = ::Time.utc(year, month, day, hour, minute, sec, usec)
+                # Time.utc(99, ...) returns a time object the year of which is 1999.
+                # 'tm.year == year' checks such cases.
+                return tm if tm.year == year
               else
-                tm = ::Time.local(year, month, day, hour, minute, sec, fsec / Rational(1000))
-                return tm if tm.utc_offset == tz_hour * 3600 + tz_min * 60
+                tm = ::Time.local(year, month, day, hour, minute, sec, usec)
+                return tm if tm.utc_offset == tz_hour * 3600 + tz_min * 60 and tm.year == year
               end
-            rescue StandardError
             end
+          rescue StandardError
           end
-          ocitimestamp_to_datetime(ary)
+          array_to_datetime(ary, timezone)
         end
 
       end
@@ -290,14 +289,38 @@
       include OCI8::BindType::Util
 
       def set(val) # :nodoc:
-        super(datetime_to_array(val, true))
+        super(datetime_to_array(val, :timestamp_tz))
       end
 
       def get() # :nodoc:
-        ocitimestamp_to_datetime(super())
+        array_to_datetime(super(), nil)
       end
     end
 
+    class LocalDateTime < OCI8::BindType::OCITimestamp
+      include OCI8::BindType::Util
+
+      def set(val) # :nodoc:
+        super(datetime_to_array(val, :timestamp))
+      end
+
+      def get() # :nodoc:
+        array_to_datetime(super(), :local)
+      end
+    end
+
+    class UTCDateTime < OCI8::BindType::OCITimestamp
+      include OCI8::BindType::Util
+
+      def set(val) # :nodoc:
+        super(datetime_to_array(val, :timestamp))
+      end
+
+      def get() # :nodoc:
+        array_to_datetime(super(), :utc)
+      end
+    end
+
     #--
     # OCI8::BindType::Time
     #++
@@ -365,202 +388,224 @@
       include OCI8::BindType::Util
 
       def set(val) # :nodoc:
-        super(datetime_to_array(val, true))
+        super(datetime_to_array(val, :timestamp_tz))
       end
 
       def get() # :nodoc:
-        ocitimestamp_to_time(super())
+        array_to_time(super(), nil)
       end
     end
 
-    if OCI8.oracle_client_version >= ORAVER_9_0
-      #--
-      # OCI8::BindType::IntervalYM
-      #++
-      #
-      # This is a helper class to select or bind Oracle data type
-      # <tt>INTERVAL YEAR TO MONTH</tt>. The retrieved value is
-      # the number of months between two timestamps.
-      #
-      # The value can be applied to \DateTime#>> to shift months.
-      # It can be applied to \Time#months_since if activisupport has
-      # been loaded.
-      #
-      # === How to select <tt>INTERVAL YEAR TO MONTH</tt>
-      #
-      # <tt>INTERVAL YEAR TO MONTH</tt> is selected as an Integer.
-      #
-      #   conn.exec("select (current_timestamp - hiredate) year to month from emp") do |hired_months|
-      #     puts "hired_months = #{hired_months}"
-      #   end
-      #
-      # == How to bind <tt>INTERVAL YEAR TO MONTH</tt>
-      #
-      # You cannot bind a bind variable as <tt>INTERVAL YEAR TO MONTH</tt> implicitly.
-      # It must be bound explicitly by OCI8::Cursor#bind_param.
-      #
-      #   # output bind variable
-      #   cursor = conn.parse(<<-EOS)
-      #     BEGIN
-      #       :interval := (:ts1 - :ts2) YEAR TO MONTH;
-      #     END;
-      #   EOS
-      #   cursor.bind_param(:interval, nil, :interval_ym)
-      #   cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
-      #   cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
-      #   cursor.exec
-      #   cursor[:interval] # => 4 (months)
-      #   cursor.close
-      #
-      #   # input bind variable
-      #   cursor = conn.parse(<<-EOS)
-      #     BEGIN
-      #       :ts1 := :ts2 + :interval;
-      #     END;
-      #   EOS
-      #   cursor.bind_param(:ts1, nil, DateTime)
-      #   cursor.bind_param(:ts2, Date.parse('1969-11-19'))
-      #   cursor.bind_param(:interval, 4, :interval_ym)
-      #   cursor.exec
-      #   cursor[:ts1].strftime('%Y-%m-%d') # => 1970-03-19
-      #   cursor.close
-      #
-      class IntervalYM < OCI8::BindType::OCIIntervalYM
-        def set(val) # :nodoc:
-          unless val.nil?
-            val = [val / 12, val % 12]
-          end
-          super(val)
+    class LocalTime < OCI8::BindType::OCITimestamp
+      include OCI8::BindType::Util
+
+      def set(val) # :nodoc:
+        super(datetime_to_array(val, :timestamp))
+      end
+
+      def get() # :nodoc:
+        array_to_time(super(), :local)
+      end
+    end
+
+    class UTCTime < OCI8::BindType::OCITimestamp
+      include OCI8::BindType::Util
+
+      def set(val) # :nodoc:
+        super(datetime_to_array(val, :timestamp))
+      end
+
+      def get() # :nodoc:
+        array_to_time(super(), :utc)
+      end
+    end
+
+    #--
+    # OCI8::BindType::IntervalYM
+    #++
+    #
+    # This is a helper class to select or bind Oracle data type
+    # <tt>INTERVAL YEAR TO MONTH</tt>. The retrieved value is
+    # the number of months between two timestamps.
+    #
+    # The value can be applied to \DateTime#>> to shift months.
+    # It can be applied to \Time#months_since if activisupport has
+    # been loaded.
+    #
+    # === How to select <tt>INTERVAL YEAR TO MONTH</tt>
+    #
+    # <tt>INTERVAL YEAR TO MONTH</tt> is selected as an Integer.
+    #
+    #   conn.exec("select (current_timestamp - hiredate) year to month from emp") do |hired_months|
+    #     puts "hired_months = #{hired_months}"
+    #   end
+    #
+    # == How to bind <tt>INTERVAL YEAR TO MONTH</tt>
+    #
+    # You cannot bind a bind variable as <tt>INTERVAL YEAR TO MONTH</tt> implicitly.
+    # It must be bound explicitly by OCI8::Cursor#bind_param.
+    #
+    #   # output bind variable
+    #   cursor = conn.parse(<<-EOS)
+    #     BEGIN
+    #       :interval := (:ts1 - :ts2) YEAR TO MONTH;
+    #     END;
+    #   EOS
+    #   cursor.bind_param(:interval, nil, :interval_ym)
+    #   cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
+    #   cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
+    #   cursor.exec
+    #   cursor[:interval] # => 4 (months)
+    #   cursor.close
+    #
+    #   # input bind variable
+    #   cursor = conn.parse(<<-EOS)
+    #     BEGIN
+    #       :ts1 := :ts2 + :interval;
+    #     END;
+    #   EOS
+    #   cursor.bind_param(:ts1, nil, DateTime)
+    #   cursor.bind_param(:ts2, Date.parse('1969-11-19'))
+    #   cursor.bind_param(:interval, 4, :interval_ym)
+    #   cursor.exec
+    #   cursor[:ts1].strftime('%Y-%m-%d') # => 1970-03-19
+    #   cursor.close
+    #
+    class IntervalYM < OCI8::BindType::OCIIntervalYM
+      def set(val) # :nodoc:
+        unless val.nil?
+          val = [val / 12, val % 12]
         end
-        def get() # :nodoc:
-          val = super()
-          return nil if val.nil?
-          year, month = val
-          year * 12 + month
-        end
-      end # OCI8::BindType::IntervalYM
+        super(val)
+      end
+      def get() # :nodoc:
+        val = super()
+        return nil if val.nil?
+        year, month = val
+        year * 12 + month
+      end
+    end # OCI8::BindType::IntervalYM
 
-      #--
-      # OCI8::BindType::IntervalDS
-      #++
+    #--
+    # OCI8::BindType::IntervalDS
+    #++
+    #
+    # (new in 2.0)
+    #
+    # This is a helper class to select or bind Oracle data type
+    # <tt>INTERVAL DAY TO SECOND</tt>. The retrieved value is
+    # the number of seconds between two typestamps as a \Float.
+    #
+    # Note that it is the number days as a \Rational if
+    # OCI8::BindType::IntervalDS.unit is :day or the ruby-oci8
+    # version is prior to 2.0.3.
+    #
+    # == How to bind <tt>INTERVAL DAY TO SECOND</tt>
+    #
+    # You cannot bind a bind variable as <tt>INTERVAL DAY TO SECOND</tt>
+    # implicitly. It must be bound explicitly by OCI8::Cursor#bind_param.
+    #
+    #   # output bind variable
+    #   cursor = conn.parse(<<-EOS)
+    #     BEGIN
+    #       :interval := (:ts1 - :ts2) DAY TO SECOND(9);
+    #     END;
+    #   EOS
+    #   cursor.bind_param(:interval, nil, :interval_ds)
+    #   cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
+    #   cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
+    #   cursor.exec
+    #   cursor[:interval] # => 10492615.0 seconds
+    #   cursor.close
+    #
+    #   # input bind variable
+    #   cursor = conn.parse(<<-EOS)
+    #     BEGIN
+    #       :ts1 := :ts2 + :interval;
+    #     END;
+    #   EOS
+    #   cursor.bind_param(:ts1, nil, DateTime)
+    #   cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
+    #   cursor.bind_param(:interval, 10492615.0, :interval_ds)
+    #   cursor.exec
+    #   cursor[:ts1].strftime('%Y-%m-%d %H:%M:%S') # => 1969-11-19 06:54:35
+    #   cursor.close
+    #
+    class IntervalDS < OCI8::BindType::OCIIntervalDS
+      @@hour = 1 / 24.to_r
+      @@minute = @@hour / 60
+      @@sec = @@minute / 60
+      @@fsec = @@sec / 1000000000
+      @@unit = :second
+
+      # call-seq:
+      #   OCI8::BindType::IntervalDS.unit -> :second or :day
       #
-      # (new in 2.0)
+      # (new in 2.0.3)
       #
-      # This is a helper class to select or bind Oracle data type
-      # <tt>INTERVAL DAY TO SECOND</tt>. The retrieved value is
-      # the number of seconds between two typestamps as a \Float.
+      # Retrieves the unit of interval.
+      def self.unit
+        @@unit
+      end
+
+      # call-seq:
+      #   OCI8::BindType::IntervalDS.unit = :second or :day
       #
-      # Note that it is the number days as a \Rational if
-      # OCI8::BindType::IntervalDS.unit is :day or the ruby-oci8
-      # version is prior to 2.0.3.
+      # (new in 2.0.3)
       #
-      # == How to bind <tt>INTERVAL DAY TO SECOND</tt>
-      #
-      # You cannot bind a bind variable as <tt>INTERVAL DAY TO SECOND</tt>
-      # implicitly. It must be bound explicitly by OCI8::Cursor#bind_param.
-      #
-      #   # output bind variable
-      #   cursor = conn.parse(<<-EOS)
-      #     BEGIN
-      #       :interval := (:ts1 - :ts2) DAY TO SECOND(9);
-      #     END;
-      #   EOS
-      #   cursor.bind_param(:interval, nil, :interval_ds)
-      #   cursor.bind_param(:ts1, DateTime.parse('1969-11-19 06:54:35 00:00'))
-      #   cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
-      #   cursor.exec
-      #   cursor[:interval] # => 10492615.0 seconds
-      #   cursor.close
-      #
-      #   # input bind variable
-      #   cursor = conn.parse(<<-EOS)
-      #     BEGIN
-      #       :ts1 := :ts2 + :interval;
-      #     END;
-      #   EOS
-      #   cursor.bind_param(:ts1, nil, DateTime)
-      #   cursor.bind_param(:ts2, DateTime.parse('1969-07-20 20:17:40 00:00'))
-      #   cursor.bind_param(:interval, 10492615.0, :interval_ds)
-      #   cursor.exec
-      #   cursor[:ts1].strftime('%Y-%m-%d %H:%M:%S') # => 1969-11-19 06:54:35
-      #   cursor.close
-      #
-      class IntervalDS < OCI8::BindType::OCIIntervalDS
-        @@hour = 1 / 24.to_r
-        @@minute = @@hour / 60
-        @@sec = @@minute / 60
-        @@fsec = @@sec / 1000000000
-        @@unit = :second
-
-        # call-seq:
-        #   OCI8::BindType::IntervalDS.unit -> :second or :day
-        #
-        # (new in 2.0.3)
-        #
-        # Retrieves the unit of interval.
-        def self.unit
-          @@unit
+      # Changes the unit of interval. :second is the default.
+      def self.unit=(val)
+        case val
+        when :second, :day
+          @@unit = val
+        else
+          raise 'unit should be :second or :day'
         end
+      end
 
-        # call-seq:
-        #   OCI8::BindType::IntervalDS.unit = :second or :day
-        #
-        # (new in 2.0.3)
-        #
-        # Changes the unit of interval. :second is the default.
-        def self.unit=(val)
-          case val
-          when :second, :day
-            @@unit = val
+      def set(val) # :nodoc:
+        unless val.nil?
+          if val < 0
+            is_minus = true
+            val = -val
           else
-            raise 'unit should be :second or :day'
+            is_minus = false
           end
-        end
-
-        def set(val) # :nodoc:
-          unless val.nil?
-            if val < 0
-              is_minus = true
-              val = -val
-            else
-              is_minus = false
-            end
-            if @@unit == :second
-              day, val = val.divmod 86400
-              hour, val = val.divmod 3600
-              minute, val = val.divmod 60
-              sec, val = val.divmod 1
-            else
-              day, val = val.divmod 1
-              hour, val = (val * 24).divmod 1
-              minute, val = (val * 60).divmod 1
-              sec, val = (val * 60).divmod 1
-            end
-            fsec, val = (val * 1000000000).divmod 1
-            if is_minus
-              day = - day
-              hour = - hour
-              minute = - minute
-              sec = - sec
-              fsec = - fsec
-            end
-            val = [day, hour, minute, sec, fsec]
-          end
-          super(val)
-        end
-
-        def get() # :nodoc:
-          val = super()
-          return nil if val.nil?
-          day, hour, minute, sec, fsec = val
           if @@unit == :second
-            fsec = fsec / 1000000000.0
-            day * 86400 + hour * 3600 + minute * 60 + sec + fsec
+            day, val = val.divmod 86400
+            hour, val = val.divmod 3600
+            minute, val = val.divmod 60
+            sec, val = val.divmod 1
           else
-            day + (hour * @@hour) + (minute * @@minute) + (sec * @@sec) + (fsec * @@fsec)
+            day, val = val.divmod 1
+            hour, val = (val * 24).divmod 1
+            minute, val = (val * 60).divmod 1
+            sec, val = (val * 60).divmod 1
           end
+          fsec, val = (val * 1000000000).divmod 1
+          if is_minus
+            day = - day
+            hour = - hour
+            minute = - minute
+            sec = - sec
+            fsec = - fsec
+          end
+          val = [day, hour, minute, sec, fsec]
         end
-      end # OCI8::BindType::IntervalDS
-    end
+        super(val)
+      end
+
+      def get() # :nodoc:
+        val = super()
+        return nil if val.nil?
+        day, hour, minute, sec, fsec = val
+        if @@unit == :second
+          fsec = fsec / 1000000000.0
+          day * 86400 + hour * 3600 + minute * 60 + sec + fsec
+        else
+          day + (hour * @@hour) + (minute * @@minute) + (sec * @@sec) + (fsec * @@fsec)
+        end
+      end
+    end # OCI8::BindType::IntervalDS
   end # OCI8::BindType
 end # OCI8

Modified: trunk/ruby-oci8/lib/oci8/object.rb
===================================================================
--- trunk/ruby-oci8/lib/oci8/object.rb	2011-10-01 04:20:02 UTC (rev 451)
+++ trunk/ruby-oci8/lib/oci8/object.rb	2011-10-09 13:26:27 UTC (rev 452)
@@ -425,7 +425,7 @@
       'INTERVAL DAY TO SECOND'  => :interval_ds,
     }
 
-    # for datetime_to_array and ocidate_to_datetime
+    # to use datetime_to_array and array_to_datetime
     extend OCI8::BindType::Util
 
     def self.check_metadata(con, metadata)
@@ -442,8 +442,8 @@
         [ATTR_FLOAT,     nil, SIZE_OF_OCINUMBER, 2, ALIGNMENT_OF_OCINUMBER]
       when :date
         [ATTR_OCIDATE,   nil, SIZE_OF_OCIDATE, 2, ALIGNMENT_OF_OCIDATE,
-         Proc.new do |val| datetime_to_array(val, false) end, # set_proc
-         Proc.new do |val| ocidate_to_datetime(val) end, # get_proc
+         Proc.new do |val| datetime_to_array(val, :date) end, # set_proc
+         Proc.new do |val| array_to_datetime(val) end, # get_proc
         ]
       when :binary_double
         [ATTR_BINARY_DOUBLE, nil, SIZE_OF_DOUBLE, 2, ALIGNMENT_OF_DOUBLE]




More information about the ruby-oci8-commit mailing list