From: Rafael Kitover Date: Fri, 26 Mar 2010 11:23:26 +0000 (+0000) Subject: InflateColumn::DateTime support for Informix X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=b0a4cf8eb18957ad8076d2b3d68bcdd787aedd18;p=dbsrgits%2FDBIx-Class-Historic.git InflateColumn::DateTime support for Informix --- diff --git a/lib/DBIx/Class/Storage/DBI/Informix.pm b/lib/DBIx/Class/Storage/DBI/Informix.pm index 575bc4b..314f4c1 100644 --- a/lib/DBIx/Class/Storage/DBI/Informix.pm +++ b/lib/DBIx/Class/Storage/DBI/Informix.pm @@ -8,6 +8,18 @@ use mro 'c3'; __PACKAGE__->mk_group_accessors('simple' => '__last_insert_id'); +=head1 NAME + +DBIx::Class::Storage::DBI::Informix - Base Storage Class for Informix Support + +=head1 DESCRIPTION + +This class implements storage-specific support for the Informix RDBMS + +=head1 METHODS + +=cut + sub _execute { my $self = shift; my ($op) = @_; @@ -47,24 +59,111 @@ sub _svp_rollback { $self->_get_dbh->do("ROLLBACK TO SAVEPOINT $name") } +=head2 connect_call_datetime_setup -1; +Used as: -__END__ + on_connect_call => 'datetime_setup' -=head1 NAME +In L to set the C and +C formats. -DBIx::Class::Storage::DBI::Informix - Base Storage Class for INFORMIX Support +Sets the following environment variables: -=head1 SYNOPSIS + GL_DATE="%m/%d/%Y" + GL_DATETIME="%Y-%m-%d %H:%M:%S%F5" -=head1 DESCRIPTION +The C and C environment variables are cleared. + +B setting the C environment variable seems to have no effect +after the process has started, so the default format is used. The C +setting does take effect however. + +The C data type supports up to 5 digits after the decimal point for +second precision, depending on how you have declared your column. The full +possible precision is used. + +The column declaration for a C with maximum precision is: + + column_name DATETIME YEAR TO FRACTION(5) -This class implements storage-specific support for Informix +The C data type stores the date portion only, and it B be declared +with: + + data_type => 'date' + +in your Result class. + +You will need the L module for inflation to work. + +=cut + +sub connect_call_datetime_setup { + my $self = shift; + + delete @ENV{qw/DBDATE DBCENTURY/}; + + $ENV{GL_DATE} = "%m/%d/%Y"; + $ENV{GL_DATETIME} = "%Y-%m-%d %H:%M:%S%F5"; +} + +sub datetime_parser_type { + 'DBIx::Class::Storage::DBI::Informix::DateTime::Format' +} + +package # hide from PAUSE + DBIx::Class::Storage::DBI::Informix::DateTime::Format; + +my $timestamp_format = '%Y-%m-%d %H:%M:%S.%5N'; # %F %T +my $date_format = '%m/%d/%Y'; + +my ($timestamp_parser, $date_parser); + +sub parse_datetime { + shift; + require DateTime::Format::Strptime; + $timestamp_parser ||= DateTime::Format::Strptime->new( + pattern => $timestamp_format, + on_error => 'croak', + ); + return $timestamp_parser->parse_datetime(shift); +} + +sub format_datetime { + shift; + require DateTime::Format::Strptime; + $timestamp_parser ||= DateTime::Format::Strptime->new( + pattern => $timestamp_format, + on_error => 'croak', + ); + return $timestamp_parser->format_datetime(shift); +} + +sub parse_date { + shift; + require DateTime::Format::Strptime; + $date_parser ||= DateTime::Format::Strptime->new( + pattern => $date_format, + on_error => 'croak', + ); + return $date_parser->parse_datetime(shift); +} + +sub format_date { + shift; + require DateTime::Format::Strptime; + $date_parser ||= DateTime::Format::Strptime->new( + pattern => $date_format, + on_error => 'croak', + ); + return $date_parser->format_datetime(shift); +} + +1; -=head1 AUTHORS +=head1 AUTHOR -See L +See L and L. =head1 LICENSE diff --git a/t/inflate/datetime_firebird.t b/t/inflate/datetime_firebird.t index 1a3136e..6d52d06 100644 --- a/t/inflate/datetime_firebird.t +++ b/t/inflate/datetime_firebird.t @@ -7,8 +7,6 @@ use lib qw(t/lib); use DBICTest; use Scope::Guard (); -# XXX we're only testing TIMESTAMP here - my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_FIREBIRD_${_}" } qw/DSN USER PASS/}; my ($dsn2, $user2, $pass2) = @ENV{map { "DBICTEST_FIREBIRD_ODBC_${_}" } qw/DSN USER PASS/}; diff --git a/t/inflate/datetime_informix.t b/t/inflate/datetime_informix.t new file mode 100644 index 0000000..af23410 --- /dev/null +++ b/t/inflate/datetime_informix.t @@ -0,0 +1,78 @@ +use strict; +use warnings; + +use Test::More; +use Test::Exception; +use lib qw(t/lib); +use DBICTest; +use Scope::Guard (); + +my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_INFORMIX_${_}" } qw/DSN USER PASS/}; + +if (not $dsn) { + plan skip_all => <<'EOF'; +Set $ENV{DBICTEST_INFORMIX_DSN} _USER and _PASS to run this test'. +Warning: This test drops and creates a table called 'event'"; +EOF +} else { + eval "use DateTime; use DateTime::Format::Strptime;"; + if ($@) { + plan skip_all => 'needs DateTime and DateTime::Format::Strptime for testing'; + } +} + +my $schema; + +{ + $schema = DBICTest::Schema->connect($dsn, $user, $pass, { + on_connect_call => [ 'datetime_setup' ], + }); + + my $sg = Scope::Guard->new(\&cleanup); + + eval { $schema->storage->dbh->do('DROP TABLE event') }; + $schema->storage->dbh->do(<<'SQL'); + CREATE TABLE event ( + id INT PRIMARY KEY, + starts_at DATE, + created_on DATETIME YEAR TO FRACTION(5) + ); +SQL + my $rs = $schema->resultset('Event'); + + my $dt = DateTime->now; + $dt->set_nanosecond(555640000); + + my $date_only = DateTime->new( + year => $dt->year, month => $dt->month, day => $dt->day + ); + + my $row; + ok( $row = $rs->create({ + id => 1, + starts_at => $date_only, + created_on => $dt, + })); + ok( $row = $rs->search({ id => 1 }, { select => [qw/starts_at created_on/] }) + ->first + ); + is $row->created_on, $dt, 'TIMESTAMP as DateTime roundtrip'; + + cmp_ok $row->created_on->nanosecond, '==', $dt->nanosecond, + 'fractional part of a second survived'; + + is $row->starts_at, $date_only, 'DATE as DateTime roundtrip'; +} + +done_testing; + +# clean up our mess +sub cleanup { + my $dbh; + eval { + $dbh = $schema->storage->dbh; + }; + return unless $dbh; + + eval { $dbh->do(qq{DROP TABLE $_}) } for qw/event/; +}