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