RDBI / rdbi

rdbi is an attempt to rewrite the core of Ruby/DBI.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Timestamp not getting saved correctly

tispratik opened this issue · comments

The following piece of code is saving current date to oracle even if my year is in 1994.
The log_time column is an oracle TIMESTAMP type. I tested it with oracle DATE also, same problem.

require "rubygems"
require 'time'
$LOAD_PATH.unshift File.dirname(__FILE__) + "/rdbi/lib/"
require "rdbi"
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'rdbi-driver-jdbc/lib/rdbi/driver/jdbc'

class Poc
  pool = RDBI::Pool.new("my_pool", [RDBI::Driver::JDBC, {:database => "oracle:thin:@XXX:1521:XXX", :username => "XXX", :password => "XXX"}], 1)
  dbh = pool.get_dbh

  dbh.prepare("insert into book(log_time) values (?)") do |s|
    s.execute(Time.parse('1994-11-05T13:15:30E*'))
  end
end

In oracle database i see:
2011-03-24 02:15:30 --> The date is current date, time is correct though.

It should actually have been stored as:
1994-11-05 02:15:30

Same code in DBI works.

require "rubygems"
require 'dbd/Jdbc'
require "dbi"

class Poc
   jdbc_url    = "dbi:Jdbc:oracle:thin:@XXX:1521:XXX"
   jdbc_driver = "oracle.jdbc.driver.OracleDriver"
   dbh = DBI.connect(jdbc_url, "XXX", "XXX", {"driver" => jdbc_driver})

   sql = "insert into book(log_time) VALUES (?)"

   dbh.prepare(sql) do |s| 
     s.execute(Time.parse('1994-11-05T13:15:30E*'))
   end 
end

The value saved in the database is: 1994-11-05 02:15:30

Can you try DateTime.parse and let me know the results?

hmm, could you try using #strftime and finding what format oracle requires for datetimes? Once I have that information, I should be able to write a patch.

For DateTime.parse

oracle/jdbc/driver/T4CTTIoer.java:440:in `processError': java.sql.SQLException: ORA-01861: literal does not match format string (NativeException)

from oracle/jdbc/driver/T4CTTIoer.java:396:in `processError'
from oracle/jdbc/driver/T4C8Oall.java:837:in `processError'
from oracle/jdbc/driver/T4CTTIfun.java:445:in `receive'
from oracle/jdbc/driver/T4CTTIfun.java:191:in `doRPC'
from oracle/jdbc/driver/T4C8Oall.java:523:in `doOALL'
from oracle/jdbc/driver/T4CPreparedStatement.java:207:in `doOall8'
from oracle/jdbc/driver/T4CPreparedStatement.java:1010:in `executeForRows'
from oracle/jdbc/driver/OracleStatement.java:1315:in `doExecuteWithTimeout'
from oracle/jdbc/driver/OraclePreparedStatement.java:3576:in `executeInternal'
from oracle/jdbc/driver/OraclePreparedStatement.java:3677:in `execute'
from oracle/jdbc/driver/OraclePreparedStatementWrapper.java:1086:in `execute'
from ./rdbi-driver-jdbc/lib/rdbi/driver/jdbc.rb:286:in `new_execution'
from /home/pratikk/Projects/test/rdbi/lib/rdbi/statement.rb:164:in `execute'
from rdbi_test.rb:26:in `Poc'
from /home/pratikk/Projects/test/rdbi/lib/rdbi/database.rb:165:in `prepare'
from rdbi_test.rb:25:in `Poc'
from rdbi_test.rb:21:in `(root)'

Am trying different strftimes, but found this patch in dbd_jdbc driver.

  module Type
    class Timestamp < DBI::Type::Null
      def self.parse(obj)
        obj = super
        return obj unless obj

        if obj.kind_of?(::DateTime) || obj.kind_of?(::Time) || obj.kind_of?(::Date)
          return obj
        elsif obj.kind_of?(::String)
          return ::DateTime.strptime(obj, "%Y-%m-%d %H:%M:%S")
        else
          return ::DateTime.parse(obj.to_s)   if obj.respond_to? :to_s
          return ::DateTime.parse(obj.to_str) if obj.respond_to? :to_str
          return obj
        end
      end
    end
  end

They also have a type conversion thing going on:

def timestamp_to_jdbctimestamp(dbitimestamp)
  cal = Calendar.getInstance()
  set_calendar_date_fields(dbitimestamp, cal)
  set_calendar_time_fields(dbitimestamp, cal)
  return java.sql.Timestamp.new(cal.getTime().getTime())
end

def jdbctimestamp_to_timestamp(jdbctimestamp)
  return nil if jdbctimestamp.nil?
  cal = get_calendar(jdbctimestamp)
  return ::DateTime.new(cal.get(Calendar::YEAR), cal.get(Calendar::MONTH)+1, cal.get(Calendar::DAY_OF_MONTH), cal.get(Calendar::HOUR_OF_DAY), cal.get(Calendar::MINUTE), cal.get(Calendar::SECOND))
end

How do we tell the prepare block that i am passing a TIMESTAMP ?

We tell by the objects class. I can't check the code out until tomorrow, but I have some ideas.

Sure. Let me know your ideas so that i can workaround the problem at hand.
Thank you very much.

having @xxx in the code sample has caused a lot of extra mail for me today.

I figured this out, I tried to take a shortcut in the JDBC driver and not use the input/output type maps. I'll work on implementing those today. I'm also moving this issue to the JDBC driver tracker.

Great! Thanks :)

this has been fixed in rdbi-driver-jdbc RDBI/rdbi-driver-jdbc@d9bd308

Thanks a lot semmons99 :)

This is broken against mysql with:
rdbi (0.9.1)
rdbi-driver-mysql (0.9.2)

Fetching from a datetime column in table A and trying to immediately insert into an identical table B using the retrieved A data fails:
d:/ruby/lib/ruby/gems/1.9.1/gems/rdbi-driver-mysql-0.9.2/lib/rdbi/driver/mys
ql.rb:408:in execute': Incorrect datetime value: '2006-02-09 18:07:27 -0500' for column 'created_at' at row 1 (Mysql::Error) from d:/ruby/lib/ruby/gems/1.9.1/gems/rdbi-driver-mysql-0.9.2/lib/rd bi/driver/mysql.rb:408:innew_execution'