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? 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
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.36.0 2022-07-22 DBI::DBD::SqlEngine::HowTo(3)