1DBI::DBD::SqlEngine::HoUwsTeor(3C)ontributed Perl DocumeDnBtIa:t:iDoBnD::SqlEngine::HowTo(3)
2
3
4

NAME

6       DBI::DBD::SqlEngine::HowTo - Guide to create DBI::DBD::SqlEngine based
7       driver
8

SYNOPSIS

10         perldoc DBI::DBD::SqlEngine::HowTo
11         perldoc DBI
12         perldoc DBI::DBD
13         perldoc DBI::DBD::SqlEngine::Developers
14         perldoc SQL::Eval
15         perldoc DBI::DBD::SqlEngine
16         perldoc DBI::DBD::SqlEngine::HowTo
17         perldoc SQL::Statement::Embed
18

DESCRIPTION

20       This document provides a step-by-step guide, how to create a new
21       "DBI::DBD::SqlEngine" based DBD. It expects that you carefully read the
22       DBI documentation and that you're familiar with DBI::DBD and had read
23       and understood DBD::ExampleP.
24
25       This document addresses experienced developers who are really sure that
26       they need to invest time when writing a new DBI Driver. Writing a DBI
27       Driver is neither a weekend project nor an easy job for hobby coders
28       after work. Expect one or two man-month of time for the first start.
29
30       Those who are still reading, should be able to sing the rules of
31       "CREATING A NEW DRIVER" in DBI::DBD.
32

CREATING DRIVER CLASSES

34       Do you have an entry in DBI's DBD registry? DBI::DBD::SqlEngine expect
35       having a unique prefix for every driver class in inheritance chain.
36
37       It's easy to get a prefix - just drop the DBI team a note
38       ("GETTING_HELP" in DBI). If you want for some reason hide your work,
39       take a look at Class::Method::Modifiers how to wrap a private prefix
40       method around existing "driver_prefix".
41
42       For this guide, a prefix of "foo_" is assumed.
43
44   Sample Skeleton
45           package DBD::Foo;
46
47           use strict;
48           use warnings;
49           use vars qw($VERSION);
50           use base qw(DBI::DBD::SqlEngine);
51
52           use DBI ();
53
54           $VERSION = "0.001";
55
56           package DBD::Foo::dr;
57
58           use vars qw(@ISA $imp_data_size);
59
60           @ISA = qw(DBI::DBD::SqlEngine::dr);
61           $imp_data_size = 0;
62
63           package DBD::Foo::db;
64
65           use vars qw(@ISA $imp_data_size);
66
67           @ISA = qw(DBI::DBD::SqlEngine::db);
68           $imp_data_size = 0;
69
70           package DBD::Foo::st;
71
72           use vars qw(@ISA $imp_data_size);
73
74           @ISA = qw(DBI::DBD::SqlEngine::st);
75           $imp_data_size = 0;
76
77           package DBD::Foo::Statement;
78
79           use vars qw(@ISA);
80
81           @ISA = qw(DBI::DBD::SqlEngine::Statement);
82
83           package DBD::Foo::Table;
84
85           use vars qw(@ISA);
86
87           @ISA = qw(DBI::DBD::SqlEngine::Table);
88
89           1;
90
91       Tiny, eh? And all you have now is a DBD named foo which will is able to
92       deal with temporary tables, as long as you use SQL::Statement. In
93       DBI::SQL::Nano environments, this DBD can do nothing.
94
95   Deal with own attributes
96       Before we start doing usable stuff with our DBI driver, we need to
97       think about what we want to do and how we want to do it.
98
99       Do we need tunable knobs accessible by users? Do we need status
100       information? All this is handled in attributes of the database handles
101       (be careful when your DBD is running "behind" a DBD::Gofer proxy).
102
103       How come the attributes into the DBD and how are they fetchable by the
104       user? Good question, but you should know because you've read the DBI
105       documentation.
106
107       "DBI::DBD::SqlEngine::db::FETCH" and "DBI::DBD::SqlEngine::db::STORE"
108       taking care for you - all they need to know is which attribute names
109       are valid and mutable or immutable. Tell them by adding
110       "init_valid_attributes" to your db class:
111
112           sub init_valid_attributes
113           {
114               my $dbh = $_[0];
115
116               $dbh->SUPER::init_valid_attributes ();
117
118               $dbh->{foo_valid_attrs} = {
119                   foo_version         => 1,   # contains version of this driver
120                   foo_valid_attrs     => 1,   # contains the valid attributes of foo drivers
121                   foo_readonly_attrs  => 1,   # contains immutable attributes of foo drivers
122                   foo_bar             => 1,   # contains the bar attribute
123                   foo_baz             => 1,   # contains the baz attribute
124                   foo_manager         => 1,   # contains the manager of the driver instance
125                   foo_manager_type    => 1,   # contains the manager class of the driver instance
126               };
127               $dbh->{foo_readonly_attrs} = {
128                   foo_version         => 1,   # ensure no-one modifies the driver version
129                   foo_valid_attrs     => 1,   # do not permit one to add more valid attributes ...
130                   foo_readonly_attrs  => 1,   # ... or make the immutable mutable
131                   foo_manager         => 1,   # manager is set internally only
132               };
133
134               return $dbh;
135           }
136
137       Woooho - but now the user cannot assign new managers? This is intended,
138       overwrite "STORE" to handle it!
139
140           sub STORE ($$$)
141           {
142               my ( $dbh, $attrib, $value ) = @_;
143
144               $dbh->SUPER::STORE( $attrib, $value );
145
146               # we're still alive, so no exception is thrown ...
147               # by DBI::DBD::SqlEngine::db::STORE
148               if ( $attrib eq "foo_manager_type" )
149               {
150                   $dbh->{foo_manager} = $dbh->{foo_manager_type}->new();
151                   # ... probably correct some states based on the new
152                   # foo_manager_type - see DBD::Sys for an example
153               }
154           }
155
156       But ... my driver runs without a manager until someone first assignes a
157       "foo_manager_type". Well, no - there're two places where you can
158       initialize defaults:
159
160           sub init_default_attributes
161           {
162               my ($dbh, $phase) = @_;
163
164               $dbh->SUPER::init_default_attributes($phase);
165
166               if( 0 == $phase )
167               {
168                   # init all attributes which have no knowledge about
169                   # user settings from DSN or the attribute hash
170                   $dbh->{foo_manager_type} = "DBD::Foo::Manager";
171               }
172               elsif( 1 == $phase )
173               {
174                   # init phase with more knowledge from DSN or attribute
175                   # hash
176                   $dbh->{foo_manager} = $dbh->{foo_manager_type}->new();
177               }
178
179               return $dbh;
180           }
181
182       So far we can prevent the users to use our database driver as data
183       storage for anything and everything. We care only about the real
184       important stuff for peace on earth and alike attributes. But in fact,
185       the driver still can't do anything. It can do less than nothing -
186       meanwhile it's not a stupid storage area anymore.
187
188   User comfort
189       "DBI::DBD::SqlEngine" since 0.05 consolidates all persistent meta data
190       of a table into a single structure stored in "$dbh->{sql_meta}". While
191       DBI::DBD::SqlEngine provides only readonly access to this structure,
192       modifications are still allowed.
193
194       Primarily DBI::DBD::SqlEngine provides access via the setters
195       "new_sql_engine_meta", "get_sql_engine_meta", "get_single_table_meta",
196       "set_single_table_meta", "set_sql_engine_meta" and
197       "clear_sql_engine_meta".  Those methods are easily accessible by the
198       users via the "$dbh->func ()" interface provided by DBI. Well, many
199       users don't feel comfortize when calling
200
201           # don't require extension for tables cars
202           $dbh->func ("cars", "f_ext", ".csv", "set_sql_engine_meta");
203
204       DBI::DBD::SqlEngine will inject a method into your driver to increase
205       the user comfort to allow:
206
207           # don't require extension for tables cars
208           $dbh->foo_set_meta ("cars", "f_ext", ".csv");
209
210       Better, but here and there users likes to do:
211
212           # don't require extension for tables cars
213           $dbh->{foo_tables}->{cars}->{f_ext} = ".csv";
214
215       This interface is provided when derived DBD's define following in
216       "init_valid_attributes" (re-capture "Deal with own attributes"):
217
218           sub init_valid_attributes
219           {
220               my $dbh = $_[0];
221
222               $dbh->SUPER::init_valid_attributes ();
223
224               $dbh->{foo_valid_attrs} = {
225                   foo_version         => 1,   # contains version of this driver
226                   foo_valid_attrs     => 1,   # contains the valid attributes of foo drivers
227                   foo_readonly_attrs  => 1,   # contains immutable attributes of foo drivers
228                   foo_bar             => 1,   # contains the bar attribute
229                   foo_baz             => 1,   # contains the baz attribute
230                   foo_manager         => 1,   # contains the manager of the driver instance
231                   foo_manager_type    => 1,   # contains the manager class of the driver instance
232                   foo_meta            => 1,   # contains the public interface to modify table meta attributes
233               };
234               $dbh->{foo_readonly_attrs} = {
235                   foo_version         => 1,   # ensure no-one modifies the driver version
236                   foo_valid_attrs     => 1,   # do not permit one to add more valid attributes ...
237                   foo_readonly_attrs  => 1,   # ... or make the immutable mutable
238                   foo_manager         => 1,   # manager is set internally only
239                   foo_meta            => 1,   # ensure public interface to modify table meta attributes are immutable
240               };
241
242               $dbh->{foo_meta} = "foo_tables";
243
244               return $dbh;
245           }
246
247       This provides a tied hash in "$dbh->{foo_tables}" and a tied hash for
248       each table's meta data in "$dbh->{foo_tables}->{$table_name}".
249       Modifications on the table meta attributes are done using the table
250       methods:
251
252           sub get_table_meta_attr { ... }
253           sub set_table_meta_attr { ... }
254
255       Both methods can adjust the attribute name for compatibility reasons,
256       e.g.  when former versions of the DBD allowed different names to be
257       used for the same flag:
258
259           my %compat_map = (
260                              abc => 'foo_abc',
261                              xyz => 'foo_xyz',
262                            );
263           __PACKAGE__->register_compat_map( \%compat_map );
264
265       If any user modification on a meta attribute needs reinitialization of
266       the meta structure (in case of "DBI::DBD::SqlEngine" these are the
267       attributes "f_file", "f_dir", "f_ext" and "f_lockfile"), inform
268       DBI::DBD::SqlEngine by doing
269
270           my %reset_on_modify = (
271                                   foo_xyz => "foo_bar",
272                                   foo_abc => "foo_bar",
273                                 );
274           __PACKAGE__->register_reset_on_modify( \%reset_on_modify );
275
276       The next access to the table meta data will force DBI::DBD::SqlEngine
277       to re-do the entire meta initialization process.
278
279       Any further action which needs to be taken can handled in
280       "table_meta_attr_changed":
281
282           sub table_meta_attr_changed
283           {
284               my ($class, $meta, $attrib, $value) = @_;
285               ...
286               $class->SUPER::table_meta_attr_changed ($meta, $attrib, $value);
287           }
288
289       This is done before the new value is set in $meta, so the attribute
290       changed handler can act depending on the old value.
291
292   Dealing with Tables
293       Let's put some life into it - it's going to be time for it.
294
295       This is a good point where a quick side step to SQL::Statement::Embed
296       will help to shorten the next paragraph. The documentation in
297       SQL::Statement::Embed regarding embedding in own DBD's works pretty
298       fine with SQL::Statement and DBI::SQL::Nano.
299
300       Second look should go to DBI::DBD::SqlEngine::Developers to get a
301       picture over the driver part of the table API. Usually there isn't much
302       to do for an easy driver.
303
304   Testing
305       Now you should have your first own DBD. Was easy, wasn't it?  But does
306       it work well? Prove it by writing tests and remember to use
307       dbd_edit_mm_attribs from DBI::DBD to ensure testing even rare cases.
308

AUTHOR

310       This guide is written by Jens Rehsack. DBI::DBD::SqlEngine is written
311       by Jens Rehsack using code from DBD::File originally written by Jochen
312       Wiedmann and Jeff Zucker.
313
314       The module DBI::DBD::SqlEngine is currently maintained by
315
316       H.Merijn Brand < h.m.brand at xs4all.nl > and Jens Rehsack  < rehsack
317       at googlemail.com >
318
320       Copyright (C) 2010 by H.Merijn Brand & Jens Rehsack
321
322       All rights reserved.
323
324       You may freely distribute and/or modify this module under the terms of
325       either the GNU General Public License (GPL) or the Artistic License, as
326       specified in the Perl README file.
327
328
329
330perl v5.28.1                      2016-04-21     DBI::DBD::SqlEngine::HowTo(3)
Impressum