File Coverage

blib/lib/Wiki/Toolkit/Setup/SQLite.pm
Criterion Covered Total %
statement 15 101 14.8
branch 0 46 0.0
condition 0 21 0.0
subroutine 5 12 41.6
pod 2 3 66.6
total 22 183 12.0


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