summaryrefslogtreecommitdiff
path: root/lib/DBD/File
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DBD/File')
-rw-r--r--lib/DBD/File/Developers.pod556
-rw-r--r--lib/DBD/File/HowTo.pod270
-rw-r--r--lib/DBD/File/Roadmap.pod176
3 files changed, 1002 insertions, 0 deletions
diff --git a/lib/DBD/File/Developers.pod b/lib/DBD/File/Developers.pod
new file mode 100644
index 0000000..a9bef85
--- /dev/null
+++ b/lib/DBD/File/Developers.pod
@@ -0,0 +1,556 @@
+=head1 NAME
+
+DBD::File::Developers - Developers documentation for DBD::File
+
+=head1 SYNOPSIS
+
+ package DBD::myDriver;
+
+ use base qw(DBD::File);
+
+ sub driver
+ {
+ ...
+ my $drh = $proto->SUPER::driver($attr);
+ ...
+ return $drh->{class};
+ }
+
+ sub CLONE { ... }
+
+ package DBD::myDriver::dr;
+
+ @ISA = qw(DBD::File::dr);
+
+ sub data_sources { ... }
+ ...
+
+ package DBD::myDriver::db;
+
+ @ISA = qw(DBD::File::db);
+
+ sub init_valid_attributes { ... }
+ sub init_default_attributes { ... }
+ sub set_versions { ... }
+ sub validate_STORE_attr { my ($dbh, $attrib, $value) = @_; ... }
+ sub validate_FETCH_attr { my ($dbh, $attrib) = @_; ... }
+ sub get_myd_versions { ... }
+
+ package DBD::myDriver::st;
+
+ @ISA = qw(DBD::File::st);
+
+ sub FETCH { ... }
+ sub STORE { ... }
+
+ package DBD::myDriver::Statement;
+
+ @ISA = qw(DBD::File::Statement);
+
+ package DBD::myDriver::Table;
+
+ @ISA = qw(DBD::File::Table);
+
+ my %reset_on_modify = (
+ myd_abc => "myd_foo",
+ myd_mno => "myd_bar",
+ );
+ __PACKAGE__->register_reset_on_modify( \%reset_on_modify );
+ my %compat_map = (
+ abc => 'foo_abc',
+ xyz => 'foo_xyz',
+ );
+ __PACKAGE__->register_compat_map( \%compat_map );
+
+ sub bootstrap_table_meta { ... }
+ sub init_table_meta { ... }
+ sub table_meta_attr_changed { ... }
+ sub open_file { ... }
+
+ sub fetch_row { ... }
+ sub push_row { ... }
+ sub push_names { ... }
+
+ # optimize the SQL engine by add one or more of
+ sub update_current_row { ... }
+ # or
+ sub update_specific_row { ... }
+ # or
+ sub update_one_row { ... }
+ # or
+ sub insert_new_row { ... }
+ # or
+ sub delete_current_row { ... }
+ # or
+ sub delete_one_row { ... }
+
+=head1 DESCRIPTION
+
+This document describes how DBD developers can write DBD::File based DBI
+drivers. It supplements L<DBI::DBD> and L<DBI::DBD::SqlEngine::Developers>,
+which you should read first.
+
+=head1 CLASSES
+
+Each DBI driver must provide a package global C<driver> method and three
+DBI related classes:
+
+=over 4
+
+=item DBD::File::dr
+
+Driver package, contains the methods DBI calls indirectly via DBI
+interface:
+
+ DBI->connect ('DBI:DBM:', undef, undef, {})
+
+ # invokes
+ package DBD::DBM::dr;
+ @DBD::DBM::dr::ISA = qw(DBD::File::dr);
+
+ sub connect ($$;$$$)
+ {
+ ...
+ }
+
+Similar for C<< data_sources () >> and C<< disconnect_all() >>.
+
+Pure Perl DBI drivers derived from DBD::File do not usually need to
+override any of the methods provided through the DBD::XXX::dr package
+however if you need additional initialization in the connect method
+you may need to.
+
+=item DBD::File::db
+
+Contains the methods which are called through DBI database handles
+(C<< $dbh >>). e.g.,
+
+ $sth = $dbh->prepare ("select * from foo");
+ # returns the f_encoding setting for table foo
+ $dbh->csv_get_meta ("foo", "f_encoding");
+
+DBD::File provides the typical methods required here. Developers who
+write DBI drivers based on DBD::File need to override the methods C<<
+set_versions >> and C<< init_valid_attributes >>.
+
+=item DBD::File::st
+
+Contains the methods to deal with prepared statement handles. e.g.,
+
+ $sth->execute () or die $sth->errstr;
+
+=back
+
+=head2 DBD::File
+
+This is the main package containing the routines to initialize
+DBD::File based DBI drivers. Primarily the C<< DBD::File::driver >>
+method is invoked, either directly from DBI when the driver is
+initialized or from the derived class.
+
+ package DBD::DBM;
+
+ use base qw( DBD::File );
+
+ sub driver
+ {
+ my ( $class, $attr ) = @_;
+ ...
+ my $drh = $class->SUPER::driver( $attr );
+ ...
+ return $drh;
+ }
+
+It is not necessary to implement your own driver method as long as
+additional initialization (e.g. installing more private driver
+methods) is not required. You do not need to call C<< setup_driver >>
+as DBD::File takes care of it.
+
+=head2 DBD::File::dr
+
+The driver package contains the methods DBI calls indirectly via the DBI
+interface (see L<DBI/DBI Class Methods>).
+
+DBD::File based DBI drivers usually do not need to implement anything here,
+it is enough to do the basic initialization:
+
+ package DBD:XXX::dr;
+
+ @DBD::XXX::dr::ISA = qw (DBD::File::dr);
+ $DBD::XXX::dr::imp_data_size = 0;
+ $DBD::XXX::dr::data_sources_attr = undef;
+ $DBD::XXX::ATTRIBUTION = "DBD::XXX $DBD::XXX::VERSION by Hans Mustermann";
+
+=head2 DBD::File::db
+
+This package defines the database methods, which are called via the DBI
+database handle C<< $dbh >>.
+
+Methods provided by DBD::File:
+
+=over 4
+
+=item ping
+
+Simply returns the content of the C<< Active >> attribute. Override
+when your driver needs more complicated actions here.
+
+=item prepare
+
+Prepares a new SQL statement to execute. Returns a statement handle,
+C<< $sth >> - instance of the DBD:XXX::st. It is neither required nor
+recommended to override this method.
+
+=item FETCH
+
+Fetches an attribute of a DBI database object. Private handle attributes
+must have a prefix (this is mandatory). If a requested attribute is
+detected as a private attribute without a valid prefix, the driver prefix
+(written as C<$drv_prefix>) is added.
+
+The driver prefix is extracted from the attribute name and verified against
+C<< $dbh->{ $drv_prefix . "valid_attrs" } >> (when it exists). If the
+requested attribute value is not listed as a valid attribute, this method
+croaks. If the attribute is valid and readonly (listed in C<< $dbh->{
+$drv_prefix . "readonly_attrs" } >> when it exists), a real copy of the
+attribute value is returned. So it's not possible to modify
+C<f_valid_attrs> from outside of DBD::File::db or a derived class.
+
+=item STORE
+
+Stores a database private attribute. Private handle attributes must have a
+prefix (this is mandatory). If a requested attribute is detected as a private
+attribute without a valid prefix, the driver prefix (written as
+C<$drv_prefix>) is added. If the database handle has an attribute
+C<${drv_prefix}_valid_attrs> - for attribute names which are not listed in
+that hash, this method croaks. If the database handle has an attribute
+C<${drv_prefix}_readonly_attrs>, only attributes which are not listed there
+can be stored (once they are initialized). Trying to overwrite such an
+immutable attribute forces this method to croak.
+
+An example of a valid attributes list can be found in
+C<< DBD::File::db::init_valid_attributes >>.
+
+=item set_versions
+
+This method sets the attribute C<f_version> with the version of DBD::File.
+
+This method is called at the begin of the C<connect ()> phase.
+
+When overriding this method, do not forget to invoke the superior one.
+
+=item init_valid_attributes
+
+This method is called after the database handle is instantiated as the
+first attribute initialization.
+
+C<< DBD::File::db::init_valid_attributes >> initializes the attributes
+C<f_valid_attrs> and C<f_readonly_attrs>.
+
+When overriding this method, do not forget to invoke the superior one,
+preferably before doing anything else. Compatibility table attribute
+access must be initialized here to allow DBD::File to instantiate the
+map tie:
+
+ # for DBD::CSV
+ $dbh->{csv_meta} = "csv_tables";
+ # for DBD::DBM
+ $dbh->{dbm_meta} = "dbm_tables";
+ # for DBD::AnyData
+ $dbh->{ad_meta} = "ad_tables";
+
+=item init_default_attributes
+
+This method is called after the database handle is instantiated to
+initialize the default attributes.
+
+C<< DBD::File::db::init_default_attributes >> initializes the attributes
+C<f_dir>, C<f_meta>, C<f_meta_map>, C<f_version>.
+
+When the derived implementor class provides the attribute to validate
+attributes (e.g. C<< $dbh->{dbm_valid_attrs} = {...}; >>) or the attribute
+containing the immutable attributes (e.g. C<< $dbh->{dbm_readonly_attrs}
+= {...}; >>), the attributes C<drv_valid_attrs>, C<drv_readonly_attrs>,
+C<drv_version> and C<drv_meta> are added (when available) to the list of
+valid and immutable attributes (where C<drv_> is interpreted as the driver
+prefix).
+
+If C<drv_meta> is set, an attribute with the name in C<drv_meta> is
+initialized providing restricted read/write access to the meta data of the
+tables using C<DBD::File::TieTables> in the first (table) level and
+C<DBD::File::TieMeta> for the meta attribute level. C<DBD::File::TieTables>
+uses C<DBD::DRV::Table::get_table_meta> to initialize the second level
+tied hash on FETCH/STORE. The C<DBD::File::TieMeta> class uses
+C<DBD::DRV::Table::get_table_meta_attr> to FETCH attribute values and
+C<DBD::DRV::Table::set_table_meta_attr> to STORE attribute values. This
+allows it to map meta attributes for compatibility reasons.
+
+=item get_single_table_meta
+
+=item get_file_meta
+
+Retrieve an attribute from a table's meta information. The method
+signature is C<< get_file_meta ($dbh, $table, $attr) >>. This method
+is called by the injected db handle method C<< ${drv_prefix}get_meta
+>>.
+
+While get_file_meta allows C<$table> or C<$attr> to be a list of tables or
+attributes to retrieve, get_single_table_meta allows only one table name
+and only one attribute name. A table name of C<'.'> (single dot) is
+interpreted as the default table and this will retrieve the appropriate
+attribute globally from the dbh. This has the same restrictions as
+C<< $dbh->{$attrib} >>.
+
+get_file_meta allows C<'+'> and C<'*'> as wildcards for table names and
+C<$table> being a regular expression matching against the table names
+(evaluated without the default table). The table name C<'*'> is
+I<all currently known tables, including the default one>. The table
+name C<'+'> is I<all table names which conform to
+ANSI file name restrictions> (/^[_A-Za-z0-9]+$/).
+
+The table meta information is retrieved using the get_table_meta and
+get_table_meta_attr methods of the table class of the implementation.
+
+=item set_single_table_meta
+
+=item set_file_meta
+
+Sets an attribute in a table's meta information. The method signature is
+C<< set_file_meta ($dbh, $table, $attr, $value) >>. This method is called
+by the injected db handle method C<< ${drv_prefix}set_meta >>.
+
+While set_file_meta allows C<$table> to be a list of tables and C<$attr>
+to be a hash of several attributes to set, set_single_table_meta allows
+only one table name and only one attribute name/value pair.
+
+The wildcard characters for the table name are the same as for
+get_file_meta.
+
+The table meta information is updated using the get_table_meta and
+set_table_meta_attr methods of the table class of the implementation.
+
+=item clear_file_meta
+
+Clears all meta information cached about a table. The method signature is
+C<< clear_file_meta ($dbh, $table) >>. This method is called
+by the injected db handle method C<< ${drv_prefix}clear_meta >>.
+
+=back
+
+=head2 DBD::File::st
+
+Contains the methods to deal with prepared statement handles:
+
+=over 4
+
+=item FETCH
+
+Fetches statement handle attributes. Supported attributes (for full overview
+see L<DBI/Statement Handle Attributes>) are C<NAME>, C<TYPE>, C<PRECISION>
+and C<NULLABLE> in case that SQL::Statement is used as SQL execution engine
+and a statement is successful prepared. When SQL::Statement has additional
+information about a table, those information are returned. Otherwise, the
+same defaults as in L<DBI::DBD::SqlEngine> are used.
+
+This method usually requires extending in a derived implementation.
+See L<DBD::CSV> or L<DBD::DBM> for some example.
+
+=back
+
+=head2 DBD::File::Statement
+
+Derives from DBI::SQL::Nano::Statement to provide following method:
+
+=over 4
+
+=item open_table
+
+Implements the open_table method required by L<SQL::Statement> and
+L<DBI::SQL::Nano>. All the work for opening the file(s) belonging to the
+table is handled and parameterized in DBD::File::Table. Unless you intend
+to add anything to the following implementation, an empty DBD::XXX::Statement
+package satisfies DBD::File.
+
+ sub open_table ($$$$$)
+ {
+ my ($self, $data, $table, $createMode, $lockMode) = @_;
+
+ my $class = ref $self;
+ $class =~ s/::Statement/::Table/;
+
+ my $flags = {
+ createMode => $createMode,
+ lockMode => $lockMode,
+ };
+ $self->{command} eq "DROP" and $flags->{dropMode} = 1;
+
+ return $class->new ($data, { table => $table }, $flags);
+ } # open_table
+
+=back
+
+=head2 DBD::File::Table
+
+Derives from DBI::SQL::Nano::Table and provides physical file access for
+the table data which are stored in the files.
+
+=over 4
+
+=item file2table
+
+This method tries to map a filename to the associated table
+name. It is called with a partially filled meta structure for the
+resulting table containing at least the following attributes:
+C<< f_ext >>, C<< f_dir >>, C<< f_lockfile >> and C<< sql_identifier_case >>.
+
+If a file/table map can be found then this method sets the C<< f_fqfn
+>>, C<< f_fqbn >>, C<< f_fqln >> and C<< table_name >> attributes in
+the meta structure. If a map cannot be found the table name will be
+undef.
+
+=item bootstrap_table_meta
+
+Initializes a table meta structure. Can be safely overridden in a
+derived class, as long as the C<< SUPER >> method is called at the end
+of the overridden method.
+
+It copies the following attributes from the database into the table meta data
+C<< f_dir >>, C<< f_ext >>, C<< f_encoding >>, C<< f_lock >>, C<< f_schema >>,
+C<< f_lockfile >> and C<< sql_identifier_case >> and makes them sticky to the
+table.
+
+This method should be called before you attempt to map between file
+name and table name to ensure the correct directory, extension etc. are
+used.
+
+=item init_table_meta
+
+Initializes more attributes of the table meta data - usually more
+expensive ones (e.g. those which require class instantiations) - when
+the file name and the table name could mapped.
+
+=item get_table_meta
+
+Returns the table meta data. If there are none for the required
+table, a new one is initialized. When it fails, nothing is
+returned. On success, the name of the table and the meta data
+structure is returned.
+
+=item get_table_meta_attr
+
+Returns a single attribute from the table meta data. If the attribute
+name appears in C<%compat_map>, the attribute name is updated from
+there.
+
+=item set_table_meta_attr
+
+Sets a single attribute in the table meta data. If the attribute
+name appears in C<%compat_map>, the attribute name is updated from
+there.
+
+=item table_meta_attr_changed
+
+Called when an attribute of the meta data is modified.
+
+If the modified attribute requires to reset a calculated attribute, the
+calculated attribute is reset (deleted from meta data structure) and
+the I<initialized> flag is removed, too. The decision is made based on
+C<%register_reset_on_modify>.
+
+=item register_reset_on_modify
+
+Allows C<set_table_meta_attr> to reset meta attributes when special
+attributes are modified. For DBD::File, modifying one of C<f_file>, C<f_dir>,
+C<f_ext> or C<f_lockfile> will reset C<f_fqfn>. DBD::DBM extends the
+list for C<dbm_type> and C<dbm_mldbm> to reset the value of C<dbm_tietype>.
+
+If your DBD has calculated values in the meta data area, then call
+C<register_reset_on_modify>:
+
+ my %reset_on_modify = ( "xxx_foo" => "xxx_bar" );
+ __PACKAGE__->register_reset_on_modify( \%reset_on_modify );
+
+=item register_compat_map
+
+Allows C<get_table_meta_attr> and C<set_table_meta_attr> to update the
+attribute name to the current favored one:
+
+ # from DBD::DBM
+ my %compat_map = ( "dbm_ext" => "f_ext" );
+ __PACKAGE__->register_compat_map( \%compat_map );
+
+=item open_file
+
+Called to open the table's data file.
+
+Depending on the attributes set in the table's meta data, the
+following steps are performed. Unless C<< f_dontopen >> is set to a
+true value, C<< f_fqfn >> must contain the full qualified file name
+for the table to work on (file2table ensures this). The encoding in
+C<< f_encoding >> is applied if set and the file is opened. If
+C<<f_fqln >> (full qualified lock name) is set, this file is opened,
+too. Depending on the value in C<< f_lock >>, the appropriate lock is
+set on the opened data file or lock file.
+
+After this is done, a derived class might add more steps in an overridden
+C<< open_file >> method.
+
+=item new
+
+Instantiates the table. This is done in 3 steps:
+
+ 1. get the table meta data
+ 2. open the data file
+ 3. bless the table data structure using inherited constructor new
+
+It is not recommended to override the constructor of the table class.
+Find a reasonable place to add you extensions in one of the above four
+methods.
+
+=item drop
+
+Implements the abstract table method for the C<< DROP >>
+command. Discards table meta data after all files belonging to the
+table are closed and unlinked.
+
+Overriding this method might be reasonable in very rare cases.
+
+=item seek
+
+Implements the abstract table method used when accessing the table from the
+engine. C<< seek >> is called every time the engine uses dumb algorithms
+for iterating over the table content.
+
+=item truncate
+
+Implements the abstract table method used when dumb table algorithms
+for C<< UPDATE >> or C<< DELETE >> need to truncate the table storage
+after the last written row.
+
+=back
+
+You should consult the documentation of C<< SQL::Eval::Table >> (see
+L<SQL::Eval>) to get more information about the abstract methods of the
+table's base class you have to override and a description of the table
+meta information expected by the SQL engines.
+
+=head1 AUTHOR
+
+The module DBD::File is currently maintained by
+
+H.Merijn Brand < h.m.brand at xs4all.nl > and
+Jens Rehsack < rehsack at googlemail.com >
+
+The original author is Jochen Wiedmann.
+
+=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
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
diff --git a/lib/DBD/File/Roadmap.pod b/lib/DBD/File/Roadmap.pod
new file mode 100644
index 0000000..804d759
--- /dev/null
+++ b/lib/DBD/File/Roadmap.pod
@@ -0,0 +1,176 @@
+=head1 NAME
+
+DBD::File::Roadmap - Planned Enhancements for DBD::File and pure Perl DBD's
+
+Jens Rehsack - May 2010
+
+=head1 SYNOPSIS
+
+This document gives a high level overview of the future of the DBD::File DBI
+driver and groundwork for pure Perl DBI drivers.
+
+The planned enhancements cover features, testing, performance, reliability,
+extensibility and more.
+
+=head1 CHANGES AND ENHANCEMENTS
+
+=head2 Features
+
+There are some features missing we would like to add, but there is
+no time plan:
+
+=over 4
+
+=item LOCK TABLE
+
+The newly implemented internal common table meta storage area would allow
+us to implement LOCK TABLE support based on file system C<flock ()>
+support.
+
+=item Transaction support
+
+While DBD::AnyData recommends explicitly committing by importing and
+exporting tables, DBD::File might be enhanced in a future version to allow
+transparent transactions using the temporary tables of SQL::Statement as
+shadow (dirty) tables.
+
+Transaction support will heavily rely on lock table support.
+
+=item Data Dictionary Persistence
+
+SQL::Statement provides dictionary information when a "CREATE TABLE ..."
+statement is executed. This dictionary is preserved for some statement
+handle attribute fetches (as C<NULLABLE> or C<PRECISION>).
+
+It is planned to extend DBD::File to support data dictionaries to work
+on the tables in it. It is not planned to support one table in different
+dictionaries, but you can have several dictionaries in one directory.
+
+=item SQL Engine selecting on connect
+
+Currently the SQL engine selected is chosen during the loading of the module
+L<DBI::SQL::Nano>. Ideally end users should be able to select the engine
+used in C<< DBI->connect () >> with a special DBD::File attribute.
+
+=back
+
+Other points of view to the planned features (and more features for the
+SQL::Statement engine) are shown in L<SQL::Statement::Roadmap>.
+
+=head2 Testing
+
+DBD::File and the dependent DBD::DBM requires a lot more automated tests
+covering API stability and compatibility with optional modules
+like SQL::Statement.
+
+=head2 Performance
+
+Several arguments for support of features like indexes on columns
+and cursors are made for DBD::CSV (which is a DBD::File based driver,
+too). Similar arguments could be made for DBD::DBM, DBD::AnyData,
+DBD::RAM or DBD::PO etc.
+
+To improve the performance of the underlying SQL engines, a clean
+reimplementation seems to be required. Currently both engines are
+prematurely optimized and therefore it is not trivial to provide
+further optimization without the risk of breaking existing features.
+
+Join the DBI developers IRC channel at L<irc://irc.perl.org/dbi> to
+participate or post to the DBI Developers Mailing List.
+
+=head2 Reliability
+
+DBD::File currently lacks the following points:
+
+=over 4
+
+=item duplicate table names
+
+It is currently possible to access a table quoted with a relative path
+(a) and additionally using an absolute path (b). If (a) and (b) are
+the same file that is not recognized (except for
+flock protection handled by the Operating System) and two independent
+tables are handled.
+
+=item invalid table names
+
+The current implementation does not prevent someone choosing a
+directory name as a physical file name for the table to open.
+
+=back
+
+=head2 Extensibility
+
+I (Jens Rehsack) have some (partially for example only) DBD's in mind:
+
+=over 4
+
+=item DBD::Sys
+
+Derive DBD::Sys from a common code base shared with DBD::File which handles
+all the emulation DBI needs (as getinfo, SQL engine handling, ...)
+
+=item DBD::Dir
+
+Provide a DBD::File derived to work with fixed table definitions through the
+file system to demonstrate how DBI / Pure Perl DBDs could handle databases
+with hierarchical structures.
+
+=item DBD::Join
+
+Provide a DBI driver which is able to manage multiple connections to other
+Databases (as DBD::Multiplex), but allow them to point to different data
+sources and allow joins between the tables of them:
+
+ # Example
+ # Let table 'lsof' being a table in DBD::Sys giving a list of open files using lsof utility
+ # Let table 'dir' being a atable from DBD::Dir
+ $sth = $dbh->prepare( "select * from dir,lsof where path='/documents' and dir.entry = lsof.filename" )
+ $sth->execute(); # gives all open files in '/documents'
+ ...
+
+ # Let table 'filesys' a DBD::Sys table of known file systems on current host
+ # Let table 'applications' a table of your Configuration Management Database
+ # where current applications (relocatable, with mountpoints for filesystems)
+ # are stored
+ $sth = dbh->prepare( "select * from applications,filesys where " .
+ "application.mountpoint = filesys.mountpoint and ".
+ "filesys.mounted is true" );
+ $sth->execute(); # gives all currently mounted applications on this host
+
+=back
+
+=head1 PRIORITIES
+
+Our priorities are focussed on current issues. Initially many new test
+cases for DBD::File and DBD::DBM should be added to the DBI test
+suite. After that some additional documentation on how to use the
+DBD::File API will be provided.
+
+Any additional priorities will come later and can be modified by (paying)
+users.
+
+=head1 RESOURCES AND CONTRIBUTIONS
+
+See L<http://dbi.perl.org/contributing> for I<how you can help>.
+
+If your company has benefited from DBI, please consider if
+it could make a donation to The Perl Foundation "DBI Development"
+fund at L<http://dbi.perl.org/donate> to secure future development.
+
+Alternatively, if your company would benefit from a specific new
+DBI feature, please consider sponsoring it's development through
+the options listed in the section "Commercial Support from the Author"
+on L<http://dbi.perl.org/support/>.
+
+Using such targeted financing allows you to contribute to DBI
+development and rapidly get something specific and directly valuable
+to you in return.
+
+My company also offers annual support contracts for the DBI, which
+provide another way to support the DBI and get something specific
+in return. Contact me for details.
+
+Thank you.
+
+=cut