diff options
Diffstat (limited to 'lib/DBD/File/HowTo.pod')
-rw-r--r-- | lib/DBD/File/HowTo.pod | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/lib/DBD/File/HowTo.pod b/lib/DBD/File/HowTo.pod new file mode 100644 index 0000000..3d45257 --- /dev/null +++ b/lib/DBD/File/HowTo.pod @@ -0,0 +1,270 @@ +=head1 NAME + +DBD::File::HowTo - Guide to create DBD::File based driver + +=head1 SYNOPSIS + + perldoc DBD::File::HowTo + perldoc DBI + perldoc DBI::DBD + perldoc DBD::File::Developers + perldoc DBI::DBD::SqlEngine::Developers + perldoc DBI::DBD::SqlEngine + perldoc SQL::Eval + perldoc DBI::DBD::SqlEngine::HowTo + perldoc SQL::Statement::Embed + perldoc DBD::File + perldoc DBD::File::HowTo + perldoc DBD::File::Developers + +=head1 DESCRIPTION + +This document provides a step-by-step guide, how to create a new +C<DBD::File> based DBD. It expects that you carefully read the L<DBI> +documentation and that you're familiar with L<DBI::DBD> and had read and +understood L<DBD::ExampleP>. + +This document addresses experienced developers who are really sure that +they need to invest time when writing a new DBI Driver. Writing a DBI +Driver is neither a weekend project nor an easy job for hobby coders +after work. Expect one or two man-month of time for the first start. + +Those who are still reading, should be able to sing the rules of +L<DBI::DBD/CREATING A NEW DRIVER>. + +Of course, DBD::File is a DBI::DBD::SqlEngine and you surely read +L<DBI::DBD::SqlEngine::HowTo> before continuing here. + +=head1 CREATING DRIVER CLASSES + +Do you have an entry in DBI's DBD registry? For this guide, a prefix of +C<foo_> is assumed. + +=head2 Sample Skeleton + + package DBD::Foo; + + use strict; + use warnings; + use vars qw(@ISA $VERSION); + use base qw(DBD::File); + + use DBI (); + + $VERSION = "0.001"; + + package DBD::Foo::dr; + + use vars qw(@ISA $imp_data_size); + + @ISA = qw(DBD::File::dr); + $imp_data_size = 0; + + package DBD::Foo::db; + + use vars qw(@ISA $imp_data_size); + + @ISA = qw(DBD::File::db); + $imp_data_size = 0; + + package DBD::Foo::st; + + use vars qw(@ISA $imp_data_size); + + @ISA = qw(DBD::File::st); + $imp_data_size = 0; + + package DBD::Foo::Statement; + + use vars qw(@ISA); + + @ISA = qw(DBD::File::Statement); + + package DBD::Foo::Table; + + use vars qw(@ISA); + + @ISA = qw(DBD::File::Table); + + 1; + +Tiny, eh? And all you have now is a DBD named foo which will is able to +deal with temporary tables, as long as you use L<SQL::Statement>. In +L<DBI::SQL::Nano> environments, this DBD can do nothing. + +=head2 Start over + +Based on L<DBI::DBD::SqlEngine::HowTo>, we're now having a driver which +could do basic things. Of course, it should now derive from DBD::File +instead of DBI::DBD::SqlEngine, shouldn't it? + +DBD::File extends DBI::DBD::SqlEngine to deal with any kind of files. +In principle, the only extensions required are to the table class: + + package DBD::Foo::Table; + + sub bootstrap_table_meta + { + my ( $self, $dbh, $meta, $table ) = @_; + + # initialize all $meta attributes which might be relevant for + # file2table + + return $self->SUPER::bootstrap_table_meta($dbh, $meta, $table); + } + + sub init_table_meta + { + my ( $self, $dbh, $meta, $table ) = @_; + + # called after $meta contains the results from file2table + # initialize all missing $meta attributes + + $self->SUPER::init_table_meta( $dbh, $meta, $table ); + } + +In case C<DBD::File::Table::open_file> doesn't open the files as the driver +needs that, override it! + + sub open_file + { + my ( $self, $meta, $attrs, $flags ) = @_; + # ensure that $meta->{f_dontopen} is set + $self->SUPER::open_file( $meta, $attrs, $flags ); + # now do what ever needs to be done + } + +Combined with the methods implemented using the L<SQL::Statement::Embed> +guide, the table is full working and you could try a start over. + +=head2 User comfort + +C<DBD::File> since C<0.39> consolidates all persistent meta data of a table +into a single structure stored in C<< $dbh->{f_meta} >>. While DBD::File +provides only readonly access to this structure, modifications are still +allowed. + +Primarily DBD::File provides access via setters C<get_file_meta>, +C<set_file_meta> and C<clear_file_meta>. Those methods are easily +accessible by the users via the C<< $dbh->func () >> interface provided +by DBI. Well, many users don't feel comfortize when calling + + # don't require extension for tables cars + $dbh->func ("cars", "f_ext", ".csv", "set_file_meta"); + +DBD::File will inject a method into your driver to increase the user +comfort to allow: + + # don't require extension for tables cars + $dbh->foo_set_meta ("cars", "f_ext", ".csv"); + +Better, but here and there users likes to do: + + # don't require extension for tables cars + $dbh->{foo_tables}->{cars}->{f_ext} = ".csv"; + +This interface is provided when derived DBD's define following in +C<init_valid_attributes> (please compare carefully with the example in +DBI::DBD::SqlEngine::HowTo): + + sub init_valid_attributes + { + my $dbh = $_[0]; + + $dbh->SUPER::init_valid_attributes (); + + $dbh->{foo_valid_attrs} = { + foo_version => 1, # contains version of this driver + foo_valid_attrs => 1, # contains the valid attributes of foo drivers + foo_readonly_attrs => 1, # contains immutable attributes of foo drivers + foo_bar => 1, # contains the bar attribute + foo_baz => 1, # contains the baz attribute + foo_manager => 1, # contains the manager of the driver instance + foo_manager_type => 1, # contains the manager class of the driver instance + foo_meta => 1, # contains the public interface to modify table meta attributes + }; + $dbh->{foo_readonly_attrs} = { + foo_version => 1, # ensure no-one modifies the driver version + foo_valid_attrs => 1, # do not permit to add more valid attributes ... + foo_readonly_attrs => 1, # ... or make the immutable mutable + foo_manager => 1, # manager is set internally only + foo_meta => 1, # ensure public interface to modify table meta attributes are immutable + }; + + $dbh->{foo_meta} = "foo_tables"; + + return $dbh; + } + +This provides a tied hash in C<< $dbh->{foo_tables} >> and a tied hash for +each table's meta data in C<< $dbh->{foo_tables}->{$table_name} >>. +Modifications on the table meta attributes are done using the table +methods: + + sub get_table_meta_attr { ... } + sub set_table_meta_attr { ... } + +Both methods can adjust the attribute name for compatibility reasons, e.g. +when former versions of the DBD allowed different names to be used for the +same flag: + + my %compat_map = ( + abc => 'foo_abc', + xyz => 'foo_xyz', + ); + __PACKAGE__->register_compat_map( \%compat_map ); + +If any user modification on a meta attribute needs reinitialization of +the meta structure (in case of C<DBD::File> these are the attributes +C<f_file>, C<f_dir>, C<f_ext> and C<f_lockfile>), inform DBD::File by +doing + + my %reset_on_modify = ( + foo_xyz => "foo_bar", + foo_abc => "foo_bar", + ); + __PACKAGE__->register_reset_on_modify( \%reset_on_modify ); + +The next access to the table meta data will force DBD::File to re-do the +entire meta initialization process. + +Any further action which needs to be taken can handled in +C<table_meta_attr_changed>: + + sub table_meta_attr_changed + { + my ($class, $meta, $attrib, $value) = @_; + ... + $class->SUPER::table_meta_attr_changed ($meta, $attrib, $value); + } + +This is done before the new value is set in C<$meta>, so the attribute +changed handler can act depending on the old value. + +=head2 Testing + +Now you should have your own DBD::File based driver. Was easy, wasn't it? +But does it work well? Prove it by writing tests and remember to use +dbd_edit_mm_attribs from L<DBI::DBD> to ensure testing even rare cases. + +=head1 AUTHOR + +This guide is written by Jens Rehsack. DBD::File is written by Jochen +Wiedmann and Jeff Zucker. + +The module DBD::File is currently maintained by + +H.Merijn Brand < h.m.brand at xs4all.nl > and +Jens Rehsack < rehsack at googlemail.com > + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2010 by H.Merijn Brand & Jens Rehsack + +All rights reserved. + +You may freely distribute and/or modify this module under the terms of +either the GNU General Public License (GPL) or the Artistic License, as +specified in the Perl README file. + +=cut |