File Coverage

blib/lib/Wiki/Toolkit/Setup/MySQL.pm
Criterion Covered Total %
statement 15 101 14.8
branch 0 54 0.0
condition 0 21 0.0
subroutine 5 12 41.6
pod 2 3 66.6
total 22 191 11.5


line stmt bran cond sub pod time code
1             package Wiki::Toolkit::Setup::MySQL;
2              
3 1     1   3928 use strict;
  1         2  
  1         37  
4              
5 1     1   6 use vars qw( @ISA $VERSION $SCHEMA_VERSION );
  1         2  
  1         53  
6              
7 1     1   453 use Wiki::Toolkit::Setup::Database;
  1         4  
  1         48  
8              
9             @ISA = qw( Wiki::Toolkit::Setup::Database );
10             $VERSION = '0.11';
11              
12 1     1   1647 use DBI;
  1         18539  
  1         70  
13 1     1   10 use Carp;
  1         2  
  1         1522  
14              
15             $SCHEMA_VERSION = $VERSION*100;
16              
17             my $create_sql = {
18             10 => {
19             schema_info => [ qq|
20             CREATE TABLE schema_info (
21             version int(10) NOT NULL default 0
22             )
23             |, qq|
24             INSERT INTO schema_info VALUES (10)
25             | ],
26              
27             node => [ qq|
28             CREATE TABLE node (
29             id integer NOT NULL AUTO_INCREMENT,
30             name varchar(200) NOT NULL DEFAULT '',
31             version int(10) NOT NULL default 0,
32             text mediumtext NOT NULL default '',
33             modified datetime default NULL,
34             moderate bool NOT NULL default '0',
35             PRIMARY KEY (id)
36             )
37             |, qq|
38             CREATE UNIQUE INDEX node_name ON node (name)
39             | ],
40              
41             content => [ qq|
42             CREATE TABLE content (
43             node_id integer NOT NULL,
44             version int(10) NOT NULL default 0,
45             text mediumtext NOT NULL default '',
46             modified datetime default NULL,
47             comment mediumtext NOT NULL default '',
48             moderated bool NOT NULL default '1',
49             verified datetime default NULL,
50             verified_info mediumtext NOT NULL default '',
51             PRIMARY KEY (node_id, version)
52             )
53             | ],
54             internal_links => [ qq|
55             CREATE TABLE internal_links (
56             link_from varchar(200) NOT NULL default '',
57             link_to varchar(200) NOT NULL default '',
58             PRIMARY KEY (link_from, link_to)
59             )
60             | ],
61             metadata => [ qq|
62             CREATE TABLE metadata (
63             node_id integer NOT NULL,
64             version int(10) NOT NULL default 0,
65             metadata_type varchar(200) NOT NULL DEFAULT '',
66             metadata_value mediumtext NOT NULL DEFAULT ''
67             )
68             |, qq|
69             CREATE INDEX metadata_index ON metadata(node_id, version, metadata_type, metadata_value(10))
70             | ]
71             },
72             11 => {
73             schema_info => [ qq|
74             CREATE TABLE schema_info (
75             version int(10) NOT NULL default 0
76             )
77             |, qq|
78             INSERT INTO schema_info VALUES (11)
79             | ],
80              
81             node => [ qq|
82             CREATE TABLE node (
83             id integer NOT NULL AUTO_INCREMENT,
84             name varchar(200) NOT NULL DEFAULT '',
85             version int(10) NOT NULL default 0,
86             text mediumtext NOT NULL,
87             modified datetime default NULL,
88             moderate bool NOT NULL default '0',
89             PRIMARY KEY (id)
90             )
91             |, qq|
92             CREATE UNIQUE INDEX node_name ON node (name)
93             | ],
94              
95             content => [ qq|
96             CREATE TABLE content (
97             node_id integer NOT NULL,
98             version int(10) NOT NULL default 0,
99             text mediumtext NOT NULL,
100             modified datetime default NULL,
101             comment mediumtext,
102             moderated bool NOT NULL default '1',
103             verified datetime default NULL,
104             verified_info mediumtext,
105             PRIMARY KEY (node_id, version)
106             )
107             | ],
108             internal_links => [ qq|
109             CREATE TABLE internal_links (
110             link_from varchar(200) NOT NULL default '',
111             link_to varchar(200) NOT NULL default '',
112             PRIMARY KEY (link_from, link_to)
113             )
114             | ],
115             metadata => [ qq|
116             CREATE TABLE metadata (
117             node_id integer NOT NULL,
118             version int(10) NOT NULL default 0,
119             metadata_type varchar(200) NOT NULL DEFAULT '',
120             metadata_value mediumtext NOT NULL
121             )
122             |, qq|
123             CREATE INDEX metadata_index ON metadata(node_id, version, metadata_type, metadata_value(10))
124             | ]
125             },
126             };
127              
128             my %fetch_upgrades = ();
129              
130             my %upgrades = (
131             '10_to_11' => [
132             qq|
133             ALTER TABLE node ALTER text DROP DEFAULT
134             |, qq|
135             ALTER TABLE content ALTER text DROP DEFAULT
136             |, qq|
137             ALTER TABLE content MODIFY comment mediumtext
138             |, qq|
139             ALTER TABLE content MODIFY verified_info mediumtext
140             |, qq|
141             ALTER TABLE metadata ALTER metadata_value DROP DEFAULT
142             |, qq|
143             UPDATE schema_info SET version = 11
144             |,
145             ],
146             );
147              
148             =head1 NAME
149              
150             Wiki::Toolkit::Setup::MySQL - Set up tables for a Wiki::Toolkit store in a MySQL database.
151              
152             =head1 SYNOPSIS
153              
154             use Wiki::Toolkit::Setup::MySQL;
155             Wiki::Toolkit::Setup::MySQL::setup($dbname, $dbuser, $dbpass, $dbhost);
156              
157             Omit $dbhost if the database is local.
158              
159             =head1 DESCRIPTION
160              
161             Set up a MySQL database for use as a Wiki::Toolkit store.
162              
163             =head1 FUNCTIONS
164              
165             =over 4
166              
167             =item B
168              
169             use Wiki::Toolkit::Setup::MySQL;
170             Wiki::Toolkit::Setup::MySQL::setup($dbname, $dbuser, $dbpass, $dbhost);
171              
172             or
173              
174             Wiki::Toolkit::Setup::Mysql::setup( $dbh );
175              
176             You can either provide an active database handle C<$dbh> or connection
177             parameters.
178              
179             If you provide connection parameters the following arguments are
180             mandatory -- the database name, the username and the password. The
181             username must be able to create and drop tables in the database.
182              
183             The $dbhost argument is optional -- omit it if the database is local.
184              
185             B If a table that the module wants to create already exists,
186             C will leave it alone. This means that you can safely run this
187             on an existing L database to bring the schema up to date
188             with the current L version. If you wish to completely start
189             again with a fresh database, run C first.
190              
191             =cut
192              
193             sub setup {
194 0     0 1   my @args = @_;
195 0           my $dbh = _get_dbh( @args );
196 0           my $disconnect_required = _disconnect_required( @args );
197 0   0       my $wanted_schema = _get_wanted_schema( @args ) || $SCHEMA_VERSION;
198              
199             die "No schema information for requested schema version $wanted_schema\n"
200 0 0         unless $create_sql->{$wanted_schema};
201              
202             # Check whether tables exist
203 0           my %tables = fetch_tables_listing($dbh, $wanted_schema);
204              
205             # Do we need to upgrade the schema of existing tables?
206             # (Don't check if no tables currently exist)
207 0           my $upgrade_schema;
208             my @cur_data;
209 0 0         if(scalar keys %tables > 0) {
210 0           $upgrade_schema = Wiki::Toolkit::Setup::Database::get_database_upgrade_required($dbh,$wanted_schema);
211             }
212 0 0         if($upgrade_schema) {
213 0 0         if ($fetch_upgrades{$upgrade_schema}) {
214             # Grab current data
215 0           print "Upgrading: $upgrade_schema\n";
216 0           @cur_data = eval("&Wiki::Toolkit::Setup::Database::fetch_upgrade_".$upgrade_schema."(\$dbh)");
217 0 0         if($@) { warn $@; }
  0            
218              
219             # Check to make sure we can create, index and drop tables
220             # before doing any more
221 0           my $perm_check = Wiki::Toolkit::Setup::Database::perm_check($dbh);
222 0 0         if ($perm_check) {
223 0           die "Unable to create/drop database tables as required by upgrade: $perm_check";
224             }
225            
226             # Drop the current tables
227 0           cleardb($dbh);
228              
229             # Grab new list of tables
230 0           %tables = fetch_tables_listing($dbh, $wanted_schema);
231             }
232             }
233              
234             # Set up tables if not found
235 0           foreach my $required ( keys %{$create_sql->{$wanted_schema}} ) {
  0            
236 0 0         if ( $tables{$required} ) {
237 0           print "Table $required already exists... skipping...\n";
238             } else {
239 0           print "Creating table $required... done\n";
240 0           foreach my $sql ( @{$create_sql->{$wanted_schema}->{$required}} ) {
  0            
241 0 0         $dbh->do($sql) or croak $dbh->errstr;
242             }
243             }
244             }
245              
246             # If upgrading, load in the new data
247 0 0         if($upgrade_schema) {
248 0 0         if ($fetch_upgrades{$upgrade_schema}) {
249 0           Wiki::Toolkit::Setup::Database::bulk_data_insert($dbh,@cur_data);
250             } else {
251 0           print "Upgrading schema: $upgrade_schema\n";
252 0           my @updates = @{$upgrades{$upgrade_schema}};
  0            
253 0           foreach my $update (@updates) {
254 0 0         if(ref($update) eq "CODE") {
    0          
255 0           &$update($dbh);
256             } elsif(ref($update) eq "ARRAY") {
257 0           foreach my $nupdate (@$update) {
258 0           $dbh->do($nupdate);
259             }
260             } else {
261 0           $dbh->do($update);
262             }
263             }
264             }
265             }
266              
267             # Clean up if we made our own dbh.
268 0 0         $dbh->disconnect if $disconnect_required;
269             }
270              
271             # Internal method - what Wiki::Toolkit tables are defined?
272             sub fetch_tables_listing {
273 0     0 0   my $dbh = shift;
274 0           my $wanted_schema = shift;
275              
276             # Check what tables exist
277 0 0         my $sth = $dbh->prepare("SHOW TABLES") or croak $dbh->errstr;
278 0           $sth->execute;
279 0           my %tables;
280 0           while ( my $table = $sth->fetchrow_array ) {
281 0 0         exists $create_sql->{$wanted_schema}->{$table} and $tables{$table} = 1;
282             }
283 0           return %tables;
284             }
285              
286             =item B
287              
288             use Wiki::Toolkit::Setup::MySQL;
289              
290             # Clear out all Wiki::Toolkit tables from the database.
291             Wiki::Toolkit::Setup::MySQL::cleardb($dbname, $dbuser, $dbpass, $dbhost);
292              
293             or
294              
295             Wiki::Toolkit::Setup::Mysql::cleardb( $dbh );
296              
297             You can either provide an active database handle C<$dbh> or connection
298             parameters.
299              
300             If you provide connection parameters the following arguments are
301             mandatory -- the database name, the username and the password. The
302             username must be able to drop tables in the database.
303              
304             The $dbhost argument is optional -- omit if the database is local.
305              
306             Clears out all L store tables from the database. B
307             that this will lose all your data; you probably only want to use this
308             for testing purposes or if you really screwed up somewhere. Note also
309             that it doesn't touch any L search backend tables; if you
310             have any of those in the same or a different database see either
311             L or L, depending on
312             which search backend you're using.
313              
314             =cut
315              
316             sub cleardb {
317 0     0 1   my @args = @_;
318 0           my $dbh = _get_dbh( @args );
319 0           my $disconnect_required = _disconnect_required( @args );
320              
321 0           print "Dropping tables... ";
322 0 0         $dbh->do("DROP TABLE IF EXISTS " . join( ",", keys %{$create_sql->{$SCHEMA_VERSION}} ) )
  0            
323             or croak $dbh->errstr;
324 0           print "done\n";
325              
326             # Clean up if we made our own dbh.
327 0 0         $dbh->disconnect if $disconnect_required;
328             }
329              
330             sub _get_dbh {
331             # Database handle passed in.
332 0 0 0 0     if ( ref $_[0] and ref $_[0] eq 'DBI::db' ) {
333 0           return $_[0];
334             }
335              
336             # Args passed as hashref.
337 0 0 0       if ( ref $_[0] and ref $_[0] eq 'HASH' ) {
338 0           my %args = %{$_[0]};
  0            
339 0 0         if ( $args{dbh} ) {
340 0           return $args{dbh};
341             } else {
342 0           return _make_dbh( %args );
343             }
344             }
345              
346             # Args passed as list of connection details.
347 0           return _make_dbh(
348             dbname => $_[0],
349             dbuser => $_[1],
350             dbpass => $_[2],
351             dbhost => $_[3],
352             );
353             }
354              
355             sub _get_wanted_schema {
356             # Database handle passed in.
357 0 0 0 0     if ( ref $_[0] and ref $_[0] eq 'DBI::db' ) {
358 0           return undef;
359             }
360              
361             # Args passed as hashref.
362 0 0 0       if ( ref $_[0] and ref $_[0] eq 'HASH' ) {
363 0           my %args = %{$_[0]};
  0            
364 0           return $args{wanted_schema};
365             }
366             }
367              
368             sub _disconnect_required {
369             # Database handle passed in.
370 0 0 0 0     if ( ref $_[0] and ref $_[0] eq 'DBI::db' ) {
371 0           return 0;
372             }
373              
374             # Args passed as hashref.
375 0 0 0       if ( ref $_[0] and ref $_[0] eq 'HASH' ) {
376 0           my %args = %{$_[0]};
  0            
377 0 0         if ( $args{dbh} ) {
378 0           return 0;
379             } else {
380 0           return 1;
381             }
382             }
383              
384             # Args passed as list of connection details.
385 0           return 1;
386             }
387              
388             sub _make_dbh {
389 0     0     my %args = @_;
390 0           my $dsn = "dbi:mysql:$args{dbname}";
391 0 0         $dsn .= ";host=$args{dbhost}" if $args{dbhost};
392             my $dbh = DBI->connect($dsn, $args{dbuser}, $args{dbpass},
393 0 0         { PrintError => 1, RaiseError => 1,
394             AutoCommit => 1 } )
395             or croak DBI::errstr;
396 0           return $dbh;
397             }
398              
399             =back
400              
401             =head1 ALTERNATIVE CALLING SYNTAX
402              
403             As requested by Podmaster. Instead of passing arguments to the methods as
404              
405             ($dbname, $dbuser, $dbpass, $dbhost)
406              
407             you can pass them as
408              
409             ( { dbname => $dbname,
410             dbuser => $dbuser,
411             dbpass => $dbpass,
412             dbhost => $dbhost
413             }
414             )
415              
416             or indeed as
417              
418             ( { dbh => $dbh } )
419              
420             Note that's a hashref, not a hash.
421              
422             =head1 AUTHOR
423              
424             Kake Pugh (kake@earth.li).
425              
426             =head1 COPYRIGHT
427              
428             Copyright (C) 2002-2004 Kake Pugh. All Rights Reserved.
429             Copyright (C) 2006-2008 the Wiki::Toolkit team. All Rights Reserved.
430              
431             This module is free software; you can redistribute it and/or modify it
432             under the same terms as Perl itself.
433              
434             =head1 SEE ALSO
435              
436             L, L, L
437              
438             =cut
439              
440             1;
441