From: Rafael Kitover Date: Mon, 8 Feb 2010 13:26:41 +0000 (+0000) Subject: better DT inflation for Firebird and _ping X-Git-Tag: v0.08121~73^2~36 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=32323fc22fa9fb54fc1a4702358450ce5a38b803;p=dbsrgits%2FDBIx-Class.git better DT inflation for Firebird and _ping --- diff --git a/lib/DBIx/Class/SQLAHacks/ODBC/Firebird.pm b/lib/DBIx/Class/SQLAHacks/ODBC/Firebird.pm deleted file mode 100644 index b6697e7..0000000 --- a/lib/DBIx/Class/SQLAHacks/ODBC/Firebird.pm +++ /dev/null @@ -1,24 +0,0 @@ -package # Hide from PAUSE - DBIx::Class::SQLAHacks::ODBC::Firebird; - -use strict; -use warnings; -use base qw( DBIx::Class::SQLAHacks ); -use Carp::Clan qw/^DBIx::Class|^SQL::Abstract/; - -sub insert { - my $self = shift; - my ($table, $vals, $opts) = @_; - -# Quoting RETURNING values breaks the Firebird ODBC driver, so we convert to -# scalarref with unquoted values. - my $returning = $opts->{returning}; - - if ($returning && ref $returning eq 'ARRAY') { - $opts->{returning} = \join ', ' => @$returning; - } - - return $self->next::method(@_); -} - -1; diff --git a/lib/DBIx/Class/Storage/DBI/InterBase.pm b/lib/DBIx/Class/Storage/DBI/InterBase.pm index 1e46215..4baa26c 100644 --- a/lib/DBIx/Class/Storage/DBI/InterBase.pm +++ b/lib/DBIx/Class/Storage/DBI/InterBase.pm @@ -24,6 +24,12 @@ L support. For ODBC support, see L. +To turn on L support, add: + + on_connect_call => 'datetime_setup' + +to your L. + =cut sub _prep_for_execute { @@ -102,29 +108,79 @@ sub _sql_maker_opts { return { limit_dialect => 'FirstSkip', %{$self->{_sql_maker_opts}||{}} }; } -sub datetime_parser_type { __PACKAGE__ } +sub _svp_begin { + my ($self, $name) = @_; + + $self->_get_dbh->do("SAVEPOINT $name"); +} + +sub _svp_release { + my ($self, $name) = @_; + + $self->_get_dbh->do("RELEASE SAVEPOINT $name"); +} + +sub _svp_rollback { + my ($self, $name) = @_; + + $self->_get_dbh->do("ROLLBACK TO SAVEPOINT $name") +} + +sub _ping { + my $self = shift; + + my $dbh = $self->_dbh or return 0; + + local $dbh->{RaiseError} = 1; + + eval { + $dbh->do('select 1 from rdb$database'); + }; + + return $@ ? 0 : 1; +} + +=head2 connect_call_datetime_setup -my ($datetime_parser, $datetime_formatter); +Used as: -sub parse_datetime { - shift; - require DateTime::Format::Strptime; - $datetime_parser ||= DateTime::Format::Strptime->new( - pattern => '%a %d %b %Y %r', -# there should be a %Z (TZ) on the end, but it's ambiguous and not parsed - on_error => 'croak', - ); - $datetime_parser->parse_datetime(shift); + on_connect_call => 'datetime_setup' + +In L to set the date and timestamp +formats using: + + $dbh->{ib_time_all} = 'ISO'; + +See L for more details. + +The C data type supports up to 4 digits after the decimal point for +second precision. The full precision is used. + +You will need the L module for inflation to work. + +For L, this is a noop and sub-second +precision is not currently available. + +=cut + +sub connect_call_datetime_setup { + my $self = shift; + + $self->_get_dbh->{ib_time_all} = 'ISO'; } -sub format_datetime { - shift; - require DateTime::Format::Strptime; - $datetime_formatter ||= DateTime::Format::Strptime->new( - pattern => '%F %H:%M:%S.%4N', - on_error => 'croak', - ); - $datetime_formatter->format_datetime(shift); + +# from MSSQL + +sub build_datetime_parser { + my $self = shift; + my $type = "DateTime::Format::Strptime"; + eval "use ${type}"; + $self->throw_exception("Couldn't load ${type}: $@") if $@; + return $type->new( + pattern => '%Y-%m-%d %H:%M:%S.%4N', # %F %T + on_error => 'croak', + ); } 1; @@ -139,16 +195,6 @@ C support only works for Firebird versions 2 or greater. To work with earlier versions, we'll need to figure out how to retrieve the bodies of C triggers and parse them for the C name. -=item * - -C values are written with precision of 4 numbers after the decimal -point for seconds, but read with only second precision. - -If you know of a session variable we can set to control how timestamps look as -strings, please let us know (via RT.) - -Otherwise we'll need to rewrite the produced SQL for timestamps, at some point. - =back =head1 AUTHOR diff --git a/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm b/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm index a17fa4a..58a3675 100644 --- a/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm +++ b/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm @@ -12,7 +12,7 @@ through ODBC =head1 SYNOPSIS -All functionality is provided by L, see +Most functionality is provided by L, see that module for details. To build the ODBC driver for Firebird on Linux for unixODBC, see: @@ -21,24 +21,29 @@ L =cut -__PACKAGE__->sql_maker_class('DBIx::Class::SQLAHacks::ODBC::Firebird'); +# XXX seemingly no equivalent to ib_time_all in DBD::InterBase via ODBC +sub connect_call_datetime_setup { 1 } -sub datetime_parser_type { __PACKAGE__ } +# from MSSQL -my $datetime_parser; - -sub parse_datetime { - shift; - require DateTime::Format::Strptime; - $datetime_parser ||= DateTime::Format::Strptime->new( - pattern => '%F %H:%M:%S', - on_error => 'croak', - ); - $datetime_parser->parse_datetime(shift); +sub build_datetime_parser { + my $self = shift; + my $type = "DateTime::Format::Strptime"; + eval "use ${type}"; + $self->throw_exception("Couldn't load ${type}: $@") if $@; + return $type->new( + pattern => '%Y-%m-%d %H:%M:%S', # %F %T + on_error => 'croak', + ); } 1; +=head1 CAVEATS + +This driver (unlike L) does not currently support reading or +writing C values with sub-second precision. + =head1 AUTHOR See L and L. diff --git a/t/750firebird.t b/t/750firebird.t index 5b79b23..0c98f95 100644 --- a/t/750firebird.t +++ b/t/750firebird.t @@ -29,7 +29,9 @@ foreach my $conn_idx (0..1) { next unless $dsn; - $schema = DBICTest::Schema->connect($dsn, $user, $pass); + $schema = DBICTest::Schema->connect($dsn, $user, $pass, { + auto_savepoint => 1 + }); my $dbh = $schema->storage->dbh; my $sg = Scope::Guard->new(\&cleanup); @@ -63,6 +65,24 @@ EOF my $new = $ars->create({ name => 'foo' }); ok($new->artistid, "Auto-PK worked"); +# test savepoints +# eval { +# $schema->txn_do(sub { +# eval { +# $schema->txn_do(sub { +# $ars->create({ name => 'in_savepoint' }); +# die "rolling back savepoint"; +# }); +# }; +# ok ((not $ars->search({ name => 'in_savepoint' })->first), +# 'savepoint rolled back'); +# $ars->create({ name => 'in_outer_txn' }); +# die "rolling back outer txn"; +# }); +# }; +# ok ((not $ars->search({ name => 'in_outer_txn' })->first), +# 'outer txn rolled back'); + # test explicit key spec $new = $ars->create ({ name => 'bar', artistid => 66 }); is($new->artistid, 66, 'Explicit PK worked'); diff --git a/t/inflate/datetime_firebird.t b/t/inflate/datetime_firebird.t index 9212f37..714c127 100644 --- a/t/inflate/datetime_firebird.t +++ b/t/inflate/datetime_firebird.t @@ -32,14 +32,12 @@ my @info = ( my $schema; -foreach my $info (@info) { - my ($dsn, $user, $pass) = @$info; +foreach my $conn_idx (0..$#info) { + my ($dsn, $user, $pass) = @{ $info[$conn_idx] }; next unless $dsn; - $schema = DBICTest::Schema->clone; - - $schema->connection($dsn, $user, $pass, { + $schema = DBICTest::Schema->connect($dsn, $user, $pass, { on_connect_call => [ 'datetime_setup' ], }); @@ -53,6 +51,7 @@ foreach my $info (@info) { ) SQL my $now = DateTime->now; + $now->set_nanosecond(555600000); my $row; ok( $row = $schema->resultset('Event')->create({ id => 1, @@ -62,7 +61,12 @@ SQL ->search({ id => 1 }, { select => ['created_on'] }) ->first ); - is( $row->created_on, $now, 'DateTime roundtrip' ); + is $row->created_on, $now, 'DateTime roundtrip'; + + if ($conn_idx == 0) { # skip for ODBC + cmp_ok $row->created_on->nanosecond, '==', 555600000, + 'fractional part of a second survived'; + } } done_testing;