From: Rafael Kitover Date: Tue, 12 Apr 2011 23:46:19 +0000 (-0400) Subject: make a proper storage base class for Firebird X-Git-Tag: v0.08191~25 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=e46df41a7023dc31ac5eba4bc81c050d7964d3be;p=dbsrgits%2FDBIx-Class.git make a proper storage base class for Firebird --- diff --git a/lib/DBIx/Class/Storage/DBI/Firebird.pm b/lib/DBIx/Class/Storage/DBI/Firebird.pm index b745581..f0178bd 100644 --- a/lib/DBIx/Class/Storage/DBI/Firebird.pm +++ b/lib/DBIx/Class/Storage/DBI/Firebird.pm @@ -2,7 +2,13 @@ package DBIx::Class::Storage::DBI::Firebird; use strict; use warnings; + +# Because DBD::Firebird is more or less a copy of +# DBD::Interbase, inherit all the workarounds contained +# in ::Storage::DBI::InterBase as opposed to inheriting +# directly from ::Storage::DBI::Firebird::Common use base qw/DBIx::Class::Storage::DBI::InterBase/; + use mro 'c3'; =head1 NAME diff --git a/lib/DBIx/Class/Storage/DBI/Firebird/Common.pm b/lib/DBIx/Class/Storage/DBI/Firebird/Common.pm new file mode 100644 index 0000000..3253b49 --- /dev/null +++ b/lib/DBIx/Class/Storage/DBI/Firebird/Common.pm @@ -0,0 +1,133 @@ +package DBIx::Class::Storage::DBI::Firebird::Common; + +use strict; +use warnings; +use base qw/DBIx::Class::Storage::DBI/; +use mro 'c3'; +use List::Util 'first'; +use namespace::clean; + +=head1 NAME + +DBIx::Class::Storage::DBI::Firebird::Common - Driver Base Class for the Firebird RDBMS + +=head1 DESCRIPTION + +This class implements autoincrements for Firebird using C as well as +L, savepoints and server +version detection. + +=cut + +# set default +__PACKAGE__->_use_insert_returning (1); +__PACKAGE__->sql_limit_dialect ('FirstSkip'); +__PACKAGE__->sql_quote_char ('"'); + +sub _sequence_fetch { + my ($self, $nextval, $sequence) = @_; + + $self->throw_exception("Can only fetch 'nextval' for a sequence") + if $nextval !~ /^nextval$/i; + + $self->throw_exception('No sequence to fetch') unless $sequence; + + my ($val) = $self->_get_dbh->selectrow_array(sprintf + 'SELECT GEN_ID(%s, 1) FROM rdb$database', + $self->sql_maker->_quote($sequence) + ); + + return $val; +} + +sub _dbh_get_autoinc_seq { + my ($self, $dbh, $source, $col) = @_; + + my $table_name = $source->from; + $table_name = $$table_name if ref $table_name; + $table_name = $self->sql_maker->quote_char ? $table_name : uc($table_name); + + local $dbh->{LongReadLen} = 100000; + local $dbh->{LongTruncOk} = 1; + + my $sth = $dbh->prepare(<<'EOF'); +SELECT t.rdb$trigger_source +FROM rdb$triggers t +WHERE t.rdb$relation_name = ? +AND t.rdb$system_flag = 0 -- user defined +AND t.rdb$trigger_type = 1 -- BEFORE INSERT +EOF + $sth->execute($table_name); + + while (my ($trigger) = $sth->fetchrow_array) { + my @trig_cols = map { + /^"([^"]+)/ ? $1 : uc($1) + } $trigger =~ /new\.("?\w+"?)/ig; + + my ($quoted, $generator) = $trigger =~ +/(?:gen_id\s* \( \s* |next \s* value \s* for \s*)(")?(\w+)/ix; + + if ($generator) { + $generator = uc $generator unless $quoted; + + return $generator + if first { + $self->sql_maker->quote_char ? ($_ eq $col) : (uc($_) eq uc($col)) + } @trig_cols; + } + } + + return undef; +} + +sub _svp_begin { + my ($self, $name) = @_; + + $self->_dbh->do("SAVEPOINT $name"); +} + +sub _svp_release { + my ($self, $name) = @_; + + $self->_dbh->do("RELEASE SAVEPOINT $name"); +} + +sub _svp_rollback { + my ($self, $name) = @_; + + $self->_dbh->do("ROLLBACK TO SAVEPOINT $name") +} + +# http://www.firebirdfaq.org/faq223/ +sub _get_server_version { + my $self = shift; + + return $self->_get_dbh->selectrow_array(q{ +SELECT rdb$get_context('SYSTEM', 'ENGINE_VERSION') FROM rdb$database + }); +} + +1; + +=head1 CAVEATS + +=over 4 + +=item * + +C support by default only works for Firebird versions 2 or +greater, L however should +work with earlier versions. + +=back + +=head1 AUTHOR + +See L and L. + +=head1 LICENSE + +You may distribute this code under the same terms as Perl itself. + +=cut +# vim:sts=2 sw=2: diff --git a/lib/DBIx/Class/Storage/DBI/InterBase.pm b/lib/DBIx/Class/Storage/DBI/InterBase.pm index 6779e47..5f5043b 100644 --- a/lib/DBIx/Class/Storage/DBI/InterBase.pm +++ b/lib/DBIx/Class/Storage/DBI/InterBase.pm @@ -2,21 +2,20 @@ package DBIx::Class::Storage::DBI::InterBase; use strict; use warnings; -use base qw/DBIx::Class::Storage::DBI/; +use base qw/DBIx::Class::Storage::DBI::Firebird::Common/; use mro 'c3'; -use List::Util 'first'; use Try::Tiny; use namespace::clean; =head1 NAME -DBIx::Class::Storage::DBI::InterBase - Driver for the Firebird RDBMS +DBIx::Class::Storage::DBI::InterBase - Driver for the Firebird RDBMS via +L =head1 DESCRIPTION -This class implements autoincrements for Firebird using C as well as -L and provides -L support. +This driver is a subclass of L for +use with L, see that driver for general details. You need to use either the L option or @@ -31,88 +30,10 @@ L. =cut -# set default -__PACKAGE__->_use_insert_returning (1); -__PACKAGE__->sql_limit_dialect ('FirstSkip'); -__PACKAGE__->sql_quote_char ('"'); __PACKAGE__->datetime_parser_type( 'DBIx::Class::Storage::DBI::InterBase::DateTime::Format' ); -sub _sequence_fetch { - my ($self, $nextval, $sequence) = @_; - - $self->throw_exception("Can only fetch 'nextval' for a sequence") - if $nextval !~ /^nextval$/i; - - $self->throw_exception('No sequence to fetch') unless $sequence; - - my ($val) = $self->_get_dbh->selectrow_array(sprintf - 'SELECT GEN_ID(%s, 1) FROM rdb$database', - $self->sql_maker->_quote($sequence) - ); - - return $val; -} - -sub _dbh_get_autoinc_seq { - my ($self, $dbh, $source, $col) = @_; - - my $table_name = $source->from; - $table_name = $$table_name if ref $table_name; - $table_name = $self->sql_maker->quote_char ? $table_name : uc($table_name); - - local $dbh->{LongReadLen} = 100000; - local $dbh->{LongTruncOk} = 1; - - my $sth = $dbh->prepare(<<'EOF'); -SELECT t.rdb$trigger_source -FROM rdb$triggers t -WHERE t.rdb$relation_name = ? -AND t.rdb$system_flag = 0 -- user defined -AND t.rdb$trigger_type = 1 -- BEFORE INSERT -EOF - $sth->execute($table_name); - - while (my ($trigger) = $sth->fetchrow_array) { - my @trig_cols = map { - /^"([^"]+)/ ? $1 : uc($1) - } $trigger =~ /new\.("?\w+"?)/ig; - - my ($quoted, $generator) = $trigger =~ -/(?:gen_id\s* \( \s* |next \s* value \s* for \s*)(")?(\w+)/ix; - - if ($generator) { - $generator = uc $generator unless $quoted; - - return $generator - if first { - $self->sql_maker->quote_char ? ($_ eq $col) : (uc($_) eq uc($col)) - } @trig_cols; - } - } - - return undef; -} - -sub _svp_begin { - my ($self, $name) = @_; - - $self->_dbh->do("SAVEPOINT $name"); -} - -sub _svp_release { - my ($self, $name) = @_; - - $self->_dbh->do("RELEASE SAVEPOINT $name"); -} - -sub _svp_rollback { - my ($self, $name) = @_; - - $self->_dbh->do("ROLLBACK TO SAVEPOINT $name") -} - sub _ping { my $self = shift; @@ -152,16 +73,6 @@ sub _set_sql_dialect { } } -sub _get_server_version { - my $self = shift; - - return $self->next::method(@_) if ref $self ne __PACKAGE__; - - local $SIG{__WARN__} = sub {}; # silence warning due to bug in DBD::InterBase - - return $self->next::method(@_); -} - =head2 connect_call_use_softcommit Used as: @@ -289,12 +200,6 @@ affects performance. Alternately, use the L driver. -=item * - -C support by default only works for Firebird versions 2 or -greater, L however should -work with earlier versions. - =back =head1 AUTHOR diff --git a/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm b/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm index b1a2a47..940b944 100644 --- a/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm +++ b/lib/DBIx/Class/Storage/DBI/ODBC/Firebird.pm @@ -2,7 +2,7 @@ package DBIx::Class::Storage::DBI::ODBC::Firebird; use strict; use warnings; -use base 'DBIx::Class::Storage::DBI::InterBase'; +use base 'DBIx::Class::Storage::DBI::Firebird::Common'; use mro 'c3'; use Try::Tiny; use namespace::clean; @@ -14,8 +14,8 @@ through ODBC =head1 DESCRIPTION -Most functionality is provided by L, see -that module for details. +Most functionality is provided by +L, see that driver for details. To build the ODBC driver for Firebird on Linux for unixODBC, see: @@ -30,15 +30,6 @@ makes it more suitable for long running processes such as under L. __PACKAGE__->datetime_parser_type ('DBIx::Class::Storage::DBI::ODBC::Firebird::DateTime::Format'); -# XXX seemingly no equivalent to ib_time_all from DBD::InterBase via ODBC -sub connect_call_datetime_setup { 1 } - -# we don't need DBD::InterBase-specific initialization -sub _init { 1 } - -# ODBC uses dialect 3 by default, good -sub _set_sql_dialect { 1 } - # releasing savepoints doesn't work for some reason, but that shouldn't matter sub _svp_release { 1 } diff --git a/t/750firebird.t b/t/750firebird.t index b2964ec..86cb433 100644 --- a/t/750firebird.t +++ b/t/750firebird.t @@ -44,7 +44,7 @@ foreach my $conn_idx (0..$#info) { auto_savepoint => 1, quote_char => q["], name_sep => q[.], - on_connect_call => 'use_softcommit', + ($dsn !~ /ODBC/ ? (on_connect_call => 'use_softcommit') : ()), }); my $dbh = $schema->storage->dbh;