From: Brandon L. Black Date: Tue, 8 Aug 2006 02:07:48 +0000 (+0000) Subject: reshuffling the division of labor between Storage and Storage::DBI (not complete) X-Git-Tag: v0.08010~43^2~34 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=046ad905e50dab1348ffca956586d7f386cfaa7e;p=dbsrgits%2FDBIx-Class.git reshuffling the division of labor between Storage and Storage::DBI (not complete) --- diff --git a/lib/DBIx/Class/Schema.pm b/lib/DBIx/Class/Schema.pm index 6eb18ba..e1f64e1 100644 --- a/lib/DBIx/Class/Schema.pm +++ b/lib/DBIx/Class/Schema.pm @@ -505,7 +505,6 @@ sub txn_do { $self->storage->txn_do(@_); } - =head2 txn_begin Begins a transaction (does nothing if AutoCommit is off). Equivalent to diff --git a/lib/DBIx/Class/Storage.pm b/lib/DBIx/Class/Storage.pm index 973f31b..3701da3 100644 --- a/lib/DBIx/Class/Storage.pm +++ b/lib/DBIx/Class/Storage.pm @@ -3,6 +3,14 @@ package DBIx::Class::Storage; use strict; use warnings; +use base qw/DBIx::Class/; + +use Scalar::Util qw/weaken/; +use Carp::Clan qw/DBIx::Class/; + +__PACKAGE__->load_components(qw/AccessorGroup/); +__PACKAGE__->mk_group_accessors('simple' => qw/debug debugobj schema/); + package # Hide from PAUSE DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION; @@ -18,29 +26,104 @@ sub new { package DBIx::Class::Storage; -sub new { die "Virtual method!" } -sub set_schema { die "Virtual method!" } -sub debug { die "Virtual method!" } -sub debugcb { die "Virtual method!" } -sub debugfh { die "Virtual method!" } -sub debugobj { die "Virtual method!" } -sub cursor { die "Virtual method!" } -sub disconnect { die "Virtual method!" } +=head1 NAME + +DBIx::Class::Storage - Generic Storage Handler + +=head1 DESCRIPTION + +A base implementation of common Storage methods. For specific +information about L-based storage, see L. + +=head1 METHODS + +=head2 new + +Arguments: $schema + +Instantiates the Storage object. + +=cut + +sub new { + my ($self, $schema) = @_; + + $self = ref $self if ref $self; + + my $new = {}; + bless $new, $self; + + $new->set_schema($schema); + $new->debugobj(new DBIx::Class::Storage::Statistics()); + + my $fh; + + my $debug_env = $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} + || $ENV{DBIC_TRACE}; + + if (defined($debug_env) && ($debug_env =~ /=(.+)$/)) { + $fh = IO::File->new($1, 'w') + or $new->throw_exception("Cannot open trace file $1"); + } else { + $fh = IO::File->new('>&STDERR'); + } + + $new->debugfh($fh); + $new->debug(1) if $debug_env; + + $new; +} + +=head2 set_schema + +Used to reset the schema class or object which owns this +storage object, such as during L. + +=cut + +sub set_schema { + my ($self, $schema) = @_; + $self->schema($schema); + weaken($self->{schema}) if ref $self->{schema}; +} + +=head2 connected + +Returns true if we have an open storage connection, false +if it is not (yet) open. + +=cut + sub connected { die "Virtual method!" } + +=head2 disconnect + +Closes any open storage connection unconditionally. + +=cut + +sub disconnect { die "Virtual method!" } + +=head2 ensure_connected + +Initiate a connection to the storage if one isn't already open. + +=cut + sub ensure_connected { die "Virtual method!" } -sub on_connect_do { die "Virtual method!" } -sub connect_info { die "Virtual method!" } -sub sql_maker { die "Virtual method!" } -sub txn_begin { die "Virtual method!" } -sub txn_commit { die "Virtual method!" } -sub txn_rollback { die "Virtual method!" } -sub insert { die "Virtual method!" } -sub update { die "Virtual method!" } -sub delete { die "Virtual method!" } -sub select { die "Virtual method!" } -sub select_single { die "Virtual method!" } -sub columns_info_for { die "Virtual method!" } -sub throw_exception { die "Virtual method!" } + +=head2 throw_exception + +Throws an exception - croaks. + +=cut + +sub throw_exception { + my $self = shift; + + $self->schema->throw_exception(@_) if $self->schema; + croak @_; +} =head2 txn_do @@ -143,4 +226,150 @@ sub txn_do { return $wantarray ? @return_values : $return_value; } +=head2 txn_begin + +Starts a transaction. + +See the preferred L method, which allows for +an entire code block to be executed transactionally. + +=cut + +sub txn_begin { die "Virtual method!" } + +=head2 txn_commit + +Issues a commit of the current transaction. + +=cut + +sub txn_commit { die "Virtual method!" } + +=head2 txn_rollback + +Issues a rollback of the current transaction. A nested rollback will +throw a L exception, +which allows the rollback to propagate to the outermost transaction. + +=cut + +sub txn_rollback { die "Virtual method!" } + +=head2 sql_maker + +Returns a C object - normally an object of class +C. + +=cut + +sub sql_maker { die "Virtual method!" } + +=head2 debug + +Causes trace information to be emitted on the C object. +(or C if C has not specifically been set). + +This is the equivalent to setting L in your +shell environment. + +=head2 debugfh + +Set or retrieve the filehandle used for trace/debug output. This should be +an IO::Handle compatible ojbect (only the C method is used. Initially +set to be STDERR - although see information on the +L environment variable. + +=cut + +sub debugfh { + my $self = shift; + + if ($self->debugobj->can('debugfh')) { + return $self->debugobj->debugfh(@_); + } +} + +=head2 debugobj + +Sets or retrieves the object used for metric collection. Defaults to an instance +of L that is compatible with the original +method of using a coderef as a callback. See the aforementioned Statistics +class for more information. + +=head2 debugcb + +Sets a callback to be executed each time a statement is run; takes a sub +reference. Callback is executed as $sub->($op, $info) where $op is +SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed. + +See L for a better way. + +=cut + +sub debugcb { + my $self = shift; + + if ($self->debugobj->can('callback')) { + return $self->debugobj->callback(@_); + } +} + +=head2 cursor + +The cursor class for this Storage object. + +=cut + +sub cursor { die "Virtual method!" } + +=head2 deploy + +Deploy the tables to storage (CREATE TABLE and friends in a SQL-based +Storage class). This would normally be called through +L. + +=cut + +sub deploy { die "Virtual method!" } + +sub on_connect_do { die "Virtual method!" } +sub connect_info { die "Virtual method!" } +sub insert { die "Virtual method!" } +sub update { die "Virtual method!" } +sub delete { die "Virtual method!" } +sub select { die "Virtual method!" } +sub select_single { die "Virtual method!" } +sub columns_info_for { die "Virtual method!" } + +=head1 ENVIRONMENT VARIABLES + +=head2 DBIC_TRACE + +If C is set then trace information +is produced (as when the L method is set). + +If the value is of the form C<1=/path/name> then the trace output is +written to the file C. + +This environment variable is checked when the storage object is first +created (when you call connect on your schema). So, run-time changes +to this environment variable will not take effect unless you also +re-connect on your schema. + +=head2 DBIX_CLASS_STORAGE_DBI_DEBUG + +Old name for DBIC_TRACE + +=head1 AUTHORS + +Matt S. Trout + +Andy Grundman + +=head1 LICENSE + +You may distribute this code under the same terms as Perl itself. + +=cut + 1; diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index 22aa2c1..8f2900e 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -10,8 +10,14 @@ use SQL::Abstract::Limit; use DBIx::Class::Storage::DBI::Cursor; use DBIx::Class::Storage::Statistics; use IO::File; -use Scalar::Util qw/weaken/; use Carp::Clan qw/DBIx::Class/; + +__PACKAGE__->mk_group_accessors( + 'simple' => + qw/_connect_info _dbh _sql_maker _sql_maker_opts _conn_pid _conn_tid + cursor on_connect_do transaction_depth/ +); + BEGIN { package DBIC::SQL::Abstract; # Would merge upstream, but nate doesn't reply :( @@ -251,14 +257,6 @@ sub name_sep { } # End of BEGIN block -use base qw/DBIx::Class/; - -__PACKAGE__->load_components(qw/AccessorGroup/); - -__PACKAGE__->mk_group_accessors('simple' => - qw/_connect_info _dbh _sql_maker _sql_maker_opts _conn_pid _conn_tid - debug debugobj cursor on_connect_do transaction_depth schema/); - =head1 NAME DBIx::Class::Storage::DBI - DBI storage handler @@ -267,69 +265,22 @@ DBIx::Class::Storage::DBI - DBI storage handler =head1 DESCRIPTION -This class represents the connection to the database +This class represents the connection to an RDBMS via L. See +L for general information. This pod only +documents DBI-specific methods and behaviors. =head1 METHODS -=head2 new - -Constructor. Only argument is the schema which instantiated us. - =cut sub new { - my ($self, $schema) = @_; + my $new = shift->next::method(@_); - my $new = {}; - bless $new, (ref $_[0] || $_[0]); - $new->set_schema($schema); $new->cursor("DBIx::Class::Storage::DBI::Cursor"); $new->transaction_depth(0); - - $new->debugobj(new DBIx::Class::Storage::Statistics()); - - my $fh; - - my $debug_env = $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} - || $ENV{DBIC_TRACE}; - - if (defined($debug_env) && ($debug_env =~ /=(.+)$/)) { - $fh = IO::File->new($1, 'w') - or $new->throw_exception("Cannot open trace file $1"); - } else { - $fh = IO::File->new('>&STDERR'); - } - $new->debugfh($fh); - $new->debug(1) if $debug_env; $new->_sql_maker_opts({}); - return $new; -} - -=head2 set_schema - -Used to reset the schema class or object which owns this -storage object, such as after a C. - -=cut -sub set_schema { - my ($self, $schema) = @_; - $self->schema($schema); - weaken($self->{schema}) if ref $self->{schema}; -} - - -=head2 throw_exception - -Throws an exception - croaks. - -=cut - -sub throw_exception { - my $self = shift; - - $self->schema->throw_exception(@_) if $self->schema; - croak @_; + $new; } =head2 connect_info @@ -437,76 +388,67 @@ Examples: ] ); -=head2 on_connect_do - -This method is deprecated in favor of setting via L. - -=head2 debug - -Causes SQL trace information to be emitted on the C object. -(or C if C has not specifically been set). - -This is the equivalent to setting L in your -shell environment. - -=head2 debugfh - -Set or retrieve the filehandle used for trace/debug output. This should be -an IO::Handle compatible ojbect (only the C method is used. Initially -set to be STDERR - although see information on the -L environment variable. - =cut -sub debugfh { - my $self = shift; - - if ($self->debugobj->can('debugfh')) { - return $self->debugobj->debugfh(@_); - } -} - -=head2 debugobj +sub connect_info { + my ($self, $info_arg) = @_; -Sets or retrieves the object used for metric collection. Defaults to an instance -of L that is campatible with the original -method of using a coderef as a callback. See the aforementioned Statistics -class for more information. + return $self->_connect_info if !$info_arg; -=head2 debugcb + # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only + # the new set of options + $self->_sql_maker(undef); + $self->_sql_maker_opts({}); -Sets a callback to be executed each time a statement is run; takes a sub -reference. Callback is executed as $sub->($op, $info) where $op is -SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed. + my $info = [ @$info_arg ]; # copy because we can alter it + my $last_info = $info->[-1]; + if(ref $last_info eq 'HASH') { + if(my $on_connect_do = delete $last_info->{on_connect_do}) { + $self->on_connect_do($on_connect_do); + } + for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) { + if(my $opt_val = delete $last_info->{$sql_maker_opt}) { + $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val; + } + } -See L for a better way. + # Get rid of any trailing empty hashref + pop(@$info) if !keys %$last_info; + } -=cut + $self->_connect_info($info); +} -sub debugcb { - my $self = shift; +=head2 on_connect_do - if ($self->debugobj->can('callback')) { - return $self->debugobj->callback(@_); - } -} +This method is deprecated in favor of setting via L. =head2 dbh_do +Arguments: $subref, @extra_coderef_args? + Execute the given subref with the underlying database handle as its first argument, using the new exception-based connection management. + +Any additional arguments will be passed verbatim to the called subref +as arguments 2 and onwards. + Example: my @stuff = $schema->storage->dbh_do( sub { - shift->selectrow_array("SELECT * FROM foo") - } + my $dbh = shift; + my $cols = join(q{, }, @_); + shift->selectrow_array("SELECT $cols FROM foo") + }, + @column_list ); =cut sub dbh_do { - my ($self, $todo) = @_; + my $self = shift; + my $todo = shift; my @result; my $want_array = wantarray; @@ -516,13 +458,13 @@ sub dbh_do { $self->_populate_dbh if !$self->_dbh; my $dbh = $self->_dbh; if($want_array) { - @result = $todo->($dbh); + @result = $todo->($dbh, @_); } elsif(defined $want_array) { - $result[0] = $todo->($dbh); + $result[0] = $todo->($dbh, @_); } else { - $todo->($dbh); + $todo->($dbh, @_); } }; @@ -533,7 +475,7 @@ sub dbh_do { : $self->_populate_dbh; my $dbh = $self->_dbh; - return $todo->($dbh); + return $todo->($dbh, @_); } return $want_array ? @result : $result[0]; @@ -541,7 +483,7 @@ sub dbh_do { =head2 disconnect -Disconnect the L handle, performing a rollback first if the +Our C method also performs a rollback first if the database is not in C mode. =cut @@ -556,13 +498,6 @@ sub disconnect { } } -=head2 connected - -Check if the L handle is connected. Returns true if the handle -is connected. - -=cut - sub connected { my ($self) = @_; @@ -592,13 +527,6 @@ sub _verify_pid { return; } -=head2 ensure_connected - -Check whether the database handle is connected - if not then make a -connection. - -=cut - sub ensure_connected { my ($self) = @_; @@ -626,13 +554,6 @@ sub _sql_maker_args { return ( limit_dialect => $self->dbh, %{$self->_sql_maker_opts} ); } -=head2 sql_maker - -Returns a C object - normally an object of class -C. - -=cut - sub sql_maker { my ($self) = @_; unless ($self->_sql_maker) { @@ -641,35 +562,6 @@ sub sql_maker { return $self->_sql_maker; } -sub connect_info { - my ($self, $info_arg) = @_; - - return $self->_connect_info if !$info_arg; - - # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only - # the new set of options - $self->_sql_maker(undef); - $self->_sql_maker_opts({}); - - my $info = [ @$info_arg ]; # copy because we can alter it - my $last_info = $info->[-1]; - if(ref $last_info eq 'HASH') { - if(my $on_connect_do = delete $last_info->{on_connect_do}) { - $self->on_connect_do($on_connect_do); - } - for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) { - if(my $opt_val = delete $last_info->{$sql_maker_opt}) { - $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val; - } - } - - # Get rid of any trailing empty hashref - pop(@$info) if !keys %$last_info; - } - - $self->_connect_info($info); -} - sub _populate_dbh { my ($self) = @_; my @info = @{$self->_connect_info || []}; @@ -727,15 +619,6 @@ sub _connect { $dbh; } -=head2 txn_begin - -Calls begin_work on the current dbh. - -See L for the txn_do() method, which allows for -an entire code block to be executed transactionally. - -=cut - sub txn_begin { my $self = shift; if ($self->{transaction_depth}++ == 0) { @@ -750,12 +633,6 @@ sub txn_begin { } } -=head2 txn_commit - -Issues a commit against the current dbh. - -=cut - sub txn_commit { my $self = shift; $self->dbh_do(sub { @@ -777,14 +654,6 @@ sub txn_commit { }); } -=head2 txn_rollback - -Issues a rollback against the current dbh. A nested rollback will -throw a L exception, -which allows the rollback to propagate to the outermost transaction. - -=cut - sub txn_rollback { my $self = shift; @@ -1128,14 +997,6 @@ sub deployment_statements { } -=head2 deploy - -Sends the appropriate statements to create or modify tables to the -db. This would normally be called through -L. - -=cut - sub deploy { my ($self, $schema, $type, $sqltargs) = @_; foreach my $statement ( $self->deployment_statements($schema, $type, undef, undef, { no_comments => 1, %{ $sqltargs || {} } } ) ) { @@ -1232,25 +1093,6 @@ For setting, this method is deprecated in favor of L. =back -=head1 ENVIRONMENT VARIABLES - -=head2 DBIC_TRACE - -If C is set then SQL trace information -is produced (as when the L method is set). - -If the value is of the form C<1=/path/name> then the trace output is -written to the file C. - -This environment variable is checked when the storage object is first -created (when you call connect on your schema). So, run-time changes -to this environment variable will not take effect unless you also -re-connect on your schema. - -=head2 DBIX_CLASS_STORAGE_DBI_DEBUG - -Old name for DBIC_TRACE - =head1 AUTHORS Matt S. Trout diff --git a/t/03podcoverage.t b/t/03podcoverage.t index 8cb8c4f..022a1c9 100644 --- a/t/03podcoverage.t +++ b/t/03podcoverage.t @@ -58,7 +58,7 @@ my $exceptions = { 'DBIx::Class::Relationship::ProxyMethods' => { skip => 1 }, 'DBIx::Class::ResultSetProxy' => { skip => 1 }, 'DBIx::Class::ResultSourceProxy' => { skip => 1 }, - 'DBIx::Class::Storage' => { skip => 1 }, + 'DBIx::Class::Storage::DBI' => { skip => 1 }, 'DBIx::Class::Storage::DBI::DB2' => { skip => 1 }, 'DBIx::Class::Storage::DBI::MSSQL' => { skip => 1 }, 'DBIx::Class::Storage::DBI::MultiDistinctEmulation' => { skip => 1 },