root/wiki-toolkit/trunk/lib/Wiki/Toolkit/Setup/SQLite.pm

Revision 504, 11.7 KB (checked in by dom, 3 years ago)

fix typos in pod (fixes #48)

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