On 22.09.2012 12:23, H.Merijn Brand wrote: > On Wed, 19 Sep 2012 17:21:32 +0200, Jens Rehsack <rehs...@cpan.org> > wrote: > >> Hi Merijn, >> >> while hacking around in DBD::File and DBI::DBD::SqlEngine I stumbled >> over a major design fault made in the past: > > Some - backward compatible - thoughts: > > Replace all dir-related parts in DBD::File with callbacks > > Make streaming interfaces able to override dir-related parts > > Backward compatible AND extendable
First shot attached as committed (svn revert for the win ^^). Needs some additional tests for streams as well as pod updates. >> sub DBD::File::Table::get_table_meta () ... evaluates >> $dbh->{f_meta}{$table}{initialized} and does something magic else. This >> magic is fully DBD::File addicted (heavily relies on file2table) and it >> should be broken into separate pieces to differ between initialisation >> done for DBI::DBD::SqlEngine and DBD::File and DBD::DBM ... >> >> I'd like to discuss it tomorrow in IRC (but I read my e-Mail if you have >> comments at the evening). >> >> If anyone else has ideas - please feel free to speak (but primary >> restriction is backward compatibility to avoid breakage of dependent DBD's). >> >> Best regards, >> Jens Best regards, Jens
Index: lib/DBI/DBD/SqlEngine.pm =================================================================== --- lib/DBI/DBD/SqlEngine.pm (Revision 15395) +++ lib/DBI/DBD/SqlEngine.pm (Arbeitskopie) @@ -206,6 +206,24 @@ return $dbh; } # connect +sub data_sources ($;$) +{ + my ( $drh, $attr ) = @_; + + my $tbl_src; + $attr + and defined $attr->{sql_table_source} + and $attr->{sql_table_source}->isa('DBI::DBD::SqlEngine::TableSource') + and $tbl_src = $attr->{sql_table_source}; + + !defined($tbl_src) + and $drh->can('default_table_source') + and $tbl_src = $drh->default_table_source(); + defined($tbl_src) or return; + + $tbl_src->data_sources( $drh, $attr ); +} # data_sources + sub disconnect_all { } # disconnect_all @@ -243,6 +261,15 @@ ( $_[0]->FETCH("Active") ) ? 1 : 0; } # ping +sub data_sources +{ + my ( $dbh, $attr, @other ) = @_; + my $drh = $dbh->{Driver}; # XXX proxy issues? + ref($attr) eq 'HASH' or $attr = {}; + defined( $attr->{sql_table_source} ) or $attr->{sql_table_source} = $dbh->{sql_table_source}; + return $drh->data_sources( $attr, @other ); +} + sub prepare ($$;@) { my ( $dbh, $statement, @attribs ) = @_; @@ -834,12 +861,23 @@ if ( $dbh->{sql_handler} eq "SQL::Statement" and $dbh->{sql_ram_tables} ) { + # XXX map +[ undef, undef, $_, "TABLE", "TEMP" ], keys %{...} foreach my $table ( keys %{ $dbh->{sql_ram_tables} } ) { push @tables, [ undef, undef, $table, "TABLE", "TEMP" ]; } } + my $tbl_src; + defined $dbh->{sql_table_source} + and $dbh->{sql_table_source}->isa('DBI::DBD::SqlEngine::TableSource') + and $tbl_src = $dbh->{sql_table_source}; + + !defined($tbl_src) + and $dbh->{Driver}->{ImplementorClass}->can('default_table_source') + and $tbl_src = $dbh->{Driver}->{ImplementorClass}->default_table_source(); + defined($tbl_src) and push( @tables, $tbl_src->avail_tables($dbh) ); + return @tables; } # get_avail_tables @@ -1269,6 +1307,48 @@ return $_[0]->{sql_stmt}{NUM_OF_ROWS}; } # rows +# ====== TableSource =========================================================== + +package DBI::DBD::SqlEngine::TableSource; + +use strict; +use warnings; + +use Carp; + +sub data_sources ($;$) +{ + my ( $class, $drh, $attrs ) = @_; + croak( ( ref( $_[0] ) ? ref( $_[0] ) : $_[0] ) . " must implement data_sources" ); +} + +sub avail_tables +{ + my ( $self, $dbh ) = @_; + croak( ( ref( $_[0] ) ? ref( $_[0] ) : $_[0] ) . " must implement avail_tables" ); +} + +# ====== DataSource ============================================================ + +package DBI::DBD::SqlEngine::DataSource; + +use strict; +use warnings; + +use Carp; + +sub complete_table_name ($$;$) +{ + my ( $self, $meta, $table, $respect_case ) = @_; + croak( ( ref( $_[0] ) ? ref( $_[0] ) : $_[0] ) . " must implement complete_table_name" ); +} + +sub open_data ($) +{ + my ( $self, $meta, $attrs, $flags ) = @_; + croak( ( ref( $_[0] ) ? ref( $_[0] ) : $_[0] ) . " must implement open_data" ); +} + # ====== SQL::STATEMENT ======================================================== package DBI::DBD::SqlEngine::Statement; @@ -1332,24 +1412,22 @@ and $meta->{readonly} = $dbh->{ReadOnly}; defined $meta->{sql_identifier_case} or $meta->{sql_identifier_case} = $dbh->{sql_identifier_case}; + + exists $meta->{sql_data_source} or $meta->{sql_data_source} = $dbh->{sql_data_source}; + + $meta; } sub init_table_meta { - my ( $self, $dbh, $meta, $table ) = @_; + my ( $self, $dbh, $meta, $table ) = @_ if(0); return; } # init_table_meta -our $respect_table_case; -sub respect_case { $respect_table_case } - -our $bootstrap_table_meta_phase = 0; -sub bootstrap_table_meta_phase { $bootstrap_table_meta_phase } - sub get_table_meta ($$$;$) { - my ( $self, $dbh, $table, $respect_case ) = @_; + my ( $self, $dbh, $table, $respect_case, @other ) = @_; unless ( defined $respect_case ) { $respect_case = 0; @@ -1367,12 +1445,10 @@ unless ( $meta->{initialized} ) { - local $bootstrap_table_meta_phase = 1; - local $respect_table_case = $respect_case; + $self->bootstrap_table_meta( $dbh, $meta, $table, @other ); + $meta->{sql_data_source}->complete_table_name( $meta, $table, $respect_case, @other ) + or return; - $self->bootstrap_table_meta( $dbh, $meta, $table ); - return unless $meta->{table_name}; - if ( defined $meta->{table_name} and $table ne $meta->{table_name} ) { $dbh->{sql_meta_map}{$table} = $meta->{table_name}; @@ -1384,13 +1460,9 @@ if ( defined $dbh->{sql_meta}{$table} && defined $dbh->{sql_meta}{$table}{initialized} ) { $meta = $dbh->{sql_meta}{$table}; - - unless ( $dbh->{sql_meta}{$table}{initialized} ) - { - $bootstrap_table_meta_phase = 2; - $self->bootstrap_table_meta( $dbh, $meta, $table ); - $meta->{table_name} or return; - } + $dbh->{sql_meta}{$table}{initialized} + or $meta->{sql_data_source}->complete_table_name( $dbh, $meta, $table, $respect_case, @other ) + or return; } unless ( $dbh->{sql_meta}{$table}{initialized} ) Index: lib/DBD/File.pm =================================================================== --- lib/DBD/File.pm (Revision 15396) +++ lib/DBD/File.pm (Arbeitskopie) @@ -97,35 +97,9 @@ return $str; } # dsn_quote -sub data_sources ($;$) -{ - my ($drh, $attr) = @_; - my $dir = $attr && exists $attr->{f_dir} - ? $attr->{f_dir} - : File::Spec->curdir (); - defined $dir or return; # Stream-based databases do not have f_dir - my %attrs; - $attr and %attrs = %$attr; - delete $attrs{f_dir}; - my $dsnextra = join ";", map { $_ . "=" . dsn_quote ($attrs{$_}) } keys %attrs; - my ($dirh) = Symbol::gensym (); - unless (opendir $dirh, $dir) { - $drh->set_err ($DBI::stderr, "Cannot open directory $dir: $!"); - return; - } +# XXX rewrite using TableConfig ... +sub default_table_source { 'DBD::File::TableSource::FileSystem' } - my ($file, @dsns, %names, $driver); - $driver = $drh->{ImplementorClass} =~ m/^dbd\:\:([^\:]+)\:\:/i ? $1 : "File"; - - while (defined ($file = readdir ($dirh))) { - my $d = File::Spec->catdir ($dir, $file); - # allow current dir ... it can be a data_source too - $file ne File::Spec->updir () && -d $d and - push @dsns, "DBI:$driver:f_dir=" . dsn_quote ($d) . ($dsnextra ? ";$dsnextra" : ""); - } - return @dsns; - } # data_sources - sub disconnect_all { } # disconnect_all @@ -152,6 +126,14 @@ @DBD::File::db::ISA = qw(DBI::DBD::SqlEngine::db); $DBD::File::db::imp_data_size = 0; +sub data_sources +{ + my ($dbh, $attr, @other) = @_; + ref($attr) eq 'HASH' or $attr = {}; + exists($attr->{f_dir}) or $attr->{f_dir} = $dbh->{f_dir}; + return $dbh->SUPER::data_sources($attr, @other); +} + sub set_versions { my $dbh = shift; @@ -204,7 +186,7 @@ # f_map is deprecated (but might return) $dbh->{f_dir} = Cwd::abs_path (File::Spec->curdir ()); - if(0) { + if(0) { # XXX remove block # complete derived attributes, if required (my $drv_class = $dbh->{ImplementorClass}) =~ s/::db$//; my $drv_prefix = DBI->driver_prefix ($drv_class); @@ -273,40 +255,6 @@ return sprintf "%s using %s", $dbh->{f_version}, $dtype; } # get_f_versions -sub get_avail_tables -{ - my $dbh = shift; - - my @tables = $dbh->SUPER::get_avail_tables (); - my $dir = $dbh->{f_dir}; - defined $dir or return; # Stream based db's cannot be queried for tables - my $dirh = Symbol::gensym (); - - unless (opendir $dirh, $dir) { - $dbh->set_err ($DBI::stderr, "Cannot open directory $dir: $!"); - return @tables; - } - - my $class = $dbh->FETCH ("ImplementorClass"); - $class =~ s/::db$/::Table/; - my ($file, %names); - my $schema = exists $dbh->{f_schema} - ? defined $dbh->{f_schema} && $dbh->{f_schema} ne "" - ? $dbh->{f_schema} : undef - : eval { getpwuid ((stat $dir)[4]) }; # XXX Win32::pwent - my %seen; - while (defined ($file = readdir ($dirh))) { - my ($tbl, $meta) = $class->get_table_meta ($dbh, $file, 0, 0) or next; # XXX - # $tbl && $meta && -f $meta->{f_fqfn} or next; - $seen{defined $schema ? $schema : "\0"}{$tbl}++ or - push @tables, [ undef, $schema, $tbl, "TABLE", "FILE" ]; - } - closedir $dirh or - $dbh->set_err ($DBI::stderr, "Cannot close directory $dir: $!"); - - return @tables; - } # get_avail_tables - # ====== STATEMENT ============================================================= package DBD::File::st; @@ -369,51 +317,179 @@ return $sth->SUPER::FETCH ($attr); } # FETCH -# ====== SQL::STATEMENT ======================================================== +# ====== TableSource =========================================================== -package DBD::File::Statement; +package DBD::File::TableSource::FileSystem; use strict; use warnings; -@DBD::File::Statement::ISA = qw( DBI::DBD::SqlEngine::Statement ); +use IO::Dir; -# ====== SQL::TABLE ============================================================ +@DBD::File::TableSource::FileSystem::ISA = 'DBI::DBD::SqlEngine::TableSource'; -package DBD::File::Table; +sub data_sources +{ + my ($class, $drh, $attr) = @_; + my $dir = $attr && exists $attr->{f_dir} + ? $attr->{f_dir} + : File::Spec->curdir (); + defined $dir or return; # Stream-based databases do not have f_dir + my %attrs; + $attr and %attrs = %$attr; + delete $attrs{f_dir}; + my $dsn_quote = $drh->can("dsn_quote"); + my $dsnextra = join ";", map { $_ . "=" . &{$dsn_quote} ($attrs{$_}) } keys %attrs; + my $dirh = IO::Dir->new($dir); + unless (defined $dirh) { + $drh->set_err ($DBI::stderr, "Cannot open directory $dir: $!"); + return; + } + my ($file, @dsns, %names, $driver); + $driver = $drh->{ImplementorClass} =~ m/^dbd\:\:([^\:]+)\:\:/i ? $1 : "File"; + + while (defined ($file = $dirh->read())) { + my $d = File::Spec->catdir ($dir, $file); + # allow current dir ... it can be a data_source too + $file ne File::Spec->updir () && -d $d and + push @dsns, "DBI:$driver:f_dir=" . dsn_quote ($d) . ($dsnextra ? ";$dsnextra" : ""); + } + return @dsns; + } # data_sources + +sub avail_tables +{ + my ($self, $dbh) = @_; + + my $dir = $dbh->{f_dir}; + defined $dir or return; # Stream based db's cannot be queried for tables + my $dirh = IO::Dir->new($dir); + + unless (defined $dirh) { + $dbh->set_err ($DBI::stderr, "Cannot open directory $dir: $!"); + return; + } + + my $class = $dbh->FETCH ("ImplementorClass"); + $class =~ s/::db$/::Table/; + my ($file, %names); + my $schema = exists $dbh->{f_schema} + ? defined $dbh->{f_schema} && $dbh->{f_schema} ne "" + ? $dbh->{f_schema} : undef + : eval { getpwuid ((stat $dir)[4]) }; # XXX Win32::pwent + my %seen; + my @tables; + while (defined ($file = $dirh->read ())) { + my ($tbl, $meta) = $class->get_table_meta ($dbh, $file, 0, 0) or next; # XXX + # $tbl && $meta && -f $meta->{f_fqfn} or next; + $seen{defined $schema ? $schema : "\0"}{$tbl}++ or + push @tables, [ undef, $schema, $tbl, "TABLE", "FILE" ]; + } + $dirh->close() or + $dbh->set_err ($DBI::stderr, "Cannot close directory $dir: $!"); + + return @tables; + } + +# ====== DataSource ============================================================ + +package DBD::File::DataSource::Stream; + use strict; use warnings; +@DBD::File::DataSource::Stream::ISA = 'DBI::DBD::SqlEngine::DataSource'; + use Carp; -require IO::File; -require File::Basename; -require File::Spec; -require Cwd; -# We may have a working flock () built-in but that doesn't mean that locking -# will work on NFS (flock () may hang hard) -my $locking = eval { flock STDOUT, 0; 1 }; +sub complete_table_name +{ + my ($self, $meta, $file, $respect_case) = @_; -@DBD::File::Table::ISA = qw( DBI::DBD::SqlEngine::Table ); + my $tbl; + if (!$respect_case and $meta->{sql_identifier_case} == 1) { # XXX SQL_IC_UPPER + $tbl = uc $tbl; + } + elsif (!$respect_case and $meta->{sql_identifier_case} == 2) { # XXX SQL_IC_LOWER + $tbl = lc $tbl; + } -# ====== FLYWEIGHT SUPPORT ===================================================== + $meta->{f_fqfn} = undef; + $meta->{f_fqbn} = undef; + $meta->{f_fqln} = undef; + $meta->{table_name} = $tbl; + + return $tbl; + } # complete_table_name + +sub apply_encoding +{ + my ($self, $meta, $fn) = @_; + defined($fn) or $fn = "file handle " . fileno($meta->{fh}); + if (my $enc = $meta->{f_encoding}) { + binmode $meta->{fh}, ":encoding($enc)" or + croak "Failed to set encoding layer '$enc' on $fn: $!"; + } + else { + binmode $meta->{fh} or croak "Failed to set binary mode on $fn: $!"; + } + } # apply_encoding + +sub open_data +{ + my ($self, $meta, $attrs, $flags) = @_; + + $flags->{dropMode} and croak "Can't drop a table in stream"; + my $fn = "file handle " . fileno($meta->{fh}); + + if ($flags->{createMode} || $flags->{lockMode}) { + $meta->{fh} = IO::Handle->new_from_fd( fileno($meta->{f_file} ), "w+" ) or + croak "Cannot open $fn for writing: $! (" . ($!+0) . ")"; + } + else { + $meta->{fh} = IO::Handle->new_from_fd( fileno($meta->{f_file} ), "r" ) or + croak "Cannot open $fn for reading: $! (" . ($!+0) . ")"; + } + + $meta->{fh} = $meta->{f_file}; + if ($meta->{fh}) { + if (my $enc = $meta->{f_encoding}) { + binmode $meta->{fh}, ":encoding($enc)" or + croak "Failed to set encoding layer '$enc' on $fn: $!"; + } + else { + binmode $meta->{fh} or croak "Failed to set binary mode on $fn: $!"; + } + } # have $meta->{$fh} + } # open_data + +package DBD::File::DataSource::File; + +use strict; +use warnings; + +@DBD::File::DataSource::File::ISA = 'DBD::File::DataSource::Stream'; + +use Carp; + my $fn_any_ext_regex = qr/\.[^.]*/; -# Flyweight support for table_info -# The functions file2table, init_table_meta, default_table_meta and -# get_table_meta are using $self arguments for polymorphism only. The -# must not rely on an instantiated DBD::File::Table -sub file2table +# We may have a working flock () built-in but that doesn't mean that locking +# will work on NFS (flock () may hang hard) +my $locking = eval { flock STDOUT, 0; 1 }; + +sub complete_table_name { - my ($self, $meta, $file, $file_is_table, $respect_case) = @_; + my ($self, $meta, $file, $respect_case, $file_is_table) = @_; $file eq "." || $file eq ".." and return; # XXX would break a possible DBD::Dir + # XXX now called without proving f_fqfn first ... my ($ext, $req) = ("", 0); if ($meta->{f_ext}) { - ($ext, my $opt) = split m/\//, $meta->{f_ext}; + ($ext, my $opt) = split m{/}, $meta->{f_ext}; if ($ext && $opt) { $opt =~ m/r/i and $req = 1; } @@ -437,7 +513,7 @@ $basename = uc $basename; $tbl = uc $tbl; } - if( !$respect_case and $meta->{sql_identifier_case} == 2) { # XXX SQL_IC_LOWER + elsif (!$respect_case and $meta->{sql_identifier_case} == 2) { # XXX SQL_IC_LOWER $basename = lc $basename; $tbl = lc $tbl; } @@ -475,12 +551,15 @@ } } - opendir my $dh, $searchdir or croak "Can't open '$searchdir': $!"; - my @f = sort { length $b <=> length $a } grep { &$cmpsub ($_) } readdir $dh; + my @f; + { + my $dh = IO::Dir->new ($searchdir) or croak "Can't open '$searchdir': $!"; + @f = sort { length $b <=> length $a } grep { &$cmpsub ($_) } $dh->read(); + $dh->close() or croak "Can't close '$searchdir': $!"; + } @f > 0 && @f <= 2 and $file = $f[0]; !$respect_case && $meta->{sql_identifier_case} == 4 and # XXX SQL_IC_MIXED ($tbl = $file) =~ s/$ext$//i; - closedir $dh or croak "Can't close '$searchdir': $!"; my $tmpfn = $file; if ($ext && $req) { @@ -501,60 +580,11 @@ $meta->{table_name} = $tbl; return $tbl; - } # file2table + } # complete_table_name -sub bootstrap_table_meta -{ - my ($self, $dbh, $meta, $table) = @_; - $self->SUPER::bootstrap_table_meta($dbh, $meta, $table); - - exists $meta->{f_dir} or $meta->{f_dir} = $dbh->{f_dir}; - defined $meta->{f_ext} or $meta->{f_ext} = $dbh->{f_ext}; - defined $meta->{f_encoding} or $meta->{f_encoding} = $dbh->{f_encoding}; - exists $meta->{f_lock} or $meta->{f_lock} = $dbh->{f_lock}; - exists $meta->{f_lockfile} or $meta->{f_lockfile} = $dbh->{f_lockfile}; - defined $meta->{f_schema} or $meta->{f_schema} = $dbh->{f_schema}; - - if ($self->bootstrap_table_meta_phase == 2 or !defined $meta->{f_fqfn}) { - $self->file2table ($meta, $table, $self->file_is_table, $self->respect_case) or delete $meta->{table_name}; - } - - } # bootstrap_table_meta - -our $file_is_a_table; -sub file_is_table { $file_is_a_table } - -sub get_table_meta ($$$$;$) +sub open_data { - my ($self, $dbh, $table, $file_is_table, $respect_case) = @_; - - local $file_is_a_table = $file_is_table; - my $meta = $self->SUPER::get_table_meta($dbh, $table, $respect_case); - $table = $meta->{table_name}; - return unless $table; - - return ($table, $meta); - } # get_table_meta - -my %reset_on_modify = ( - f_file => "f_fqfn", - f_dir => "f_fqfn", - f_ext => "f_fqfn", - f_lockfile => "f_fqfn", # forces new file2table call - ); - -__PACKAGE__->register_reset_on_modify( \%reset_on_modify ); - -my %compat_map = map { $_ => "f_$_" } qw( file ext lock lockfile ); - -__PACKAGE__->register_compat_map( \%compat_map ); - - -# ====== FILE OPEN ============================================================= - -sub open_file ($$$) -{ my ($self, $meta, $attrs, $flags) = @_; defined $meta->{f_fqfn} && $meta->{f_fqfn} ne "" or croak "No filename given"; @@ -574,19 +604,14 @@ } } + $meta->{fh} = $fh; + if ($fh) { $fh->seek (0, 0) or croak "Error while seeking back: $!"; - if (my $enc = $meta->{f_encoding}) { - binmode $fh, ":encoding($enc)" or - croak "Failed to set encoding layer '$enc' on $fn: $!"; - } - else { - binmode $fh or croak "Failed to set binary mode on $fn: $!"; - } + + $self->apply_encoding($meta); } - - $meta->{fh} = $fh; } if ($meta->{f_fqln}) { $fn = $meta->{f_fqln}; @@ -618,8 +643,131 @@ } # $lm = 0 is forced no locking at all } - } # open_file + } +# ====== SQL::STATEMENT ======================================================== + +package DBD::File::Statement; + +use strict; +use warnings; + +@DBD::File::Statement::ISA = qw( DBI::DBD::SqlEngine::Statement ); + +# ====== SQL::TABLE ============================================================ + +package DBD::File::Table; + +use strict; +use warnings; + +use Carp; +require IO::File; +require File::Basename; +require File::Spec; +require Cwd; +require Scalar::Util; + +@DBD::File::Table::ISA = qw( DBI::DBD::SqlEngine::Table ); + +# ====== UTILITIES ============================================================ + +if ( eval { require Params::Util; } ) +{ + Params::Util->import("_HANDLE"); +} +else +{ + # taken but modified from Params::Util ... + *_HANDLE = sub { + # It has to be defined, of course + defined $_[0] or return; + + # Normal globs are considered to be file handles + ref $_[0] eq 'GLOB' and return $_[0]; + + # Check for a normal tied filehandle + # Side Note: 5.5.4's tied() and can() doesn't like getting undef + tied($_[0]) and tied($_[0])->can('TIEHANDLE') and return $_[0]; + + # There are no other non-object handles that we support + Scalar::Util::blessed($_[0]) or return; + + # Check for a common base classes for conventional IO::Handle object + $_[0]->isa('IO::Handle') and return $_[0]; + + # Check for tied file handles using Tie::Handle + $_[0]->isa('Tie::Handle') and return $_[0]; + + # IO::Scalar is not a proper seekable, but it is valid is a + # regular file handle + $_[0]->isa('IO::Scalar') and return $_[0]; + + # Yet another special case for IO::String, which refuses (for now + # anyway) to become a subclass of IO::Handle. + $_[0]->isa('IO::String') and return $_[0]; + + # This is not any sort of object we know about + return; + }; +} + +# ====== FLYWEIGHT SUPPORT ===================================================== + +# Flyweight support for table_info +# The functions file2table, init_table_meta, default_table_meta and +# get_table_meta are using $self arguments for polymorphism only. The +# must not rely on an instantiated DBD::File::Table +sub file2table +{ + my ($self, $meta, $file, $file_is_table, $respect_case) = @_; + + return $meta->{sql_data_source}->complete_table_name($meta, $file, $respect_case, $file_is_table); + } # file2table + +sub bootstrap_table_meta +{ + my ($self, $dbh, $meta, $table, @other) = @_; + + $self->SUPER::bootstrap_table_meta($dbh, $meta, $table, @other); + + exists $meta->{f_dir} or $meta->{f_dir} = $dbh->{f_dir}; + defined $meta->{f_ext} or $meta->{f_ext} = $dbh->{f_ext}; + defined $meta->{f_encoding} or $meta->{f_encoding} = $dbh->{f_encoding}; + exists $meta->{f_lock} or $meta->{f_lock} = $dbh->{f_lock}; + exists $meta->{f_lockfile} or $meta->{f_lockfile} = $dbh->{f_lockfile}; + defined $meta->{f_schema} or $meta->{f_schema} = $dbh->{f_schema}; + + defined ($meta->{sql_data_source}) or + $meta->{sql_data_source} = _HANDLE ($meta->{f_file}) + ? 'DBD::File::DataSource::Stream' + : 'DBD::File::DataSource::File'; + } # bootstrap_table_meta + +sub get_table_meta ($$$$;$) +{ + my ($self, $dbh, $table, $file_is_table, $respect_case) = @_; + + my $meta = $self->SUPER::get_table_meta($dbh, $table, $respect_case, $file_is_table); + $table = $meta->{table_name}; + return unless $table; + + return ($table, $meta); + } # get_table_meta + +my %reset_on_modify = ( + f_file => "f_fqfn", + f_dir => "f_fqfn", + f_ext => "f_fqfn", + f_lockfile => "f_fqfn", # forces new file2table call + ); + +__PACKAGE__->register_reset_on_modify( \%reset_on_modify ); + +my %compat_map = map { $_ => "f_$_" } qw( file ext lock lockfile ); + +__PACKAGE__->register_compat_map( \%compat_map ); + # ====== SQL::Eval API ========================================================= sub new @@ -630,7 +778,7 @@ # because column name mapping is initialized in constructor ... my ($tblnm, $meta) = $className->get_table_meta ($data->{Database}, $attrs->{table}, 1) or croak "Cannot find appropriate file for table '$attrs->{table}'"; - $className->open_file ($meta, $attrs, $flags); + $meta->{sql_data_source}->open_data ($meta, $attrs, $flags); return $className->SUPER::new ($data, $attrs, $flags); } # new Index: lib/DBD/DBM.pm =================================================================== --- lib/DBD/DBM.pm (Revision 15390) +++ lib/DBD/DBM.pm (Arbeitskopie) @@ -255,17 +255,6 @@ my $dirfext = $^O eq 'VMS' ? '.sdbm_dir' : '.dir'; -sub file2table -{ - my ( $self, $meta, $file, $file_is_table, $quoted ) = @_; - - my $tbl = $self->SUPER::file2table( $meta, $file, $file_is_table, $quoted ) or return; - - $meta->{f_dontopen} = 1; - - return $tbl; -} - my %reset_on_modify = ( dbm_type => "dbm_tietype", dbm_mldbm => "dbm_tietype", @@ -321,6 +310,8 @@ { my ( $self, $dbh, $meta, $table ) = @_; + $meta->{f_dontopen} = 1; + unless ( defined( $meta->{dbm_tietype} ) ) { my $tie_type = $meta->{dbm_type};