File Coverage

blib/lib/Rubric/DBI/Setup.pm
Criterion Covered Total %
statement 41 57 71.9
branch 7 22 31.8
condition n/a
subroutine 12 13 92.3
pod 6 6 100.0
total 66 98 67.3


line stmt bran cond sub pod time code
1 7     7   31393 use strict;
  7         15  
  7         159  
2 7     7   26 use warnings;
  7         14  
  7         235  
3             # ABSTRACT: db initialization routines
4              
5             #pod =head1 SYNOPSIS
6             #pod
7             #pod use strict;
8             #pod use warnings;
9             #pod
10             #pod use Rubric::DBI::Setup;
11             #pod Rubric::DBI::Setup->setup_tables;
12             #pod
13             #pod =head1 DESCRIPTION
14             #pod
15             #pod =cut
16              
17             use DBI;
18 7     7   4412 use Rubric::Config;
  7         51811  
  7         302  
19 7     7   46 use Rubric::Entry;
  7         13  
  7         45  
20 7     7   1538 use Rubric::Renderer;
  7         23  
  7         73  
21 7     7   2426  
  7         25  
  7         7662  
22             #pod =head1 METHODS
23             #pod
24             #pod =head2 dbh
25             #pod
26             #pod This method returns a connection to the Rubric database.
27             #pod
28             #pod =cut
29              
30             my $dbh;
31              
32             return $dbh if $dbh;
33              
34 15 100   15 1 122707 return $dbh = DBI->connect(
35             Rubric::Config->dsn,
36 2         16 Rubric::Config->db_user,
37             Rubric::Config->db_pass
38             );
39             }
40              
41             #pod =head2 setup_tables
42             #pod
43             #pod This method builds the tables in the database, if needed.
44             #pod
45             #pod =cut
46              
47             my ($class) = @_;
48              
49             local $/ = "\n\n";
50 2     2 1 2058 $class->dbh->do( $class->specialize_sql($_) ) for <DATA>;
51             }
52 2         13  
53 2         49 #pod =head2 specialize_sql
54             #pod
55             #pod attempts to convert the given sql syntax to the given DBD Driver's
56             #pod
57             #pod =cut
58              
59             my ($class, $query) = @_;
60              
61             my $db_type = $class->determine_db_type;
62              
63 12     12 1 17797 if ($db_type eq 'Pg') {
64             $query =~ s/(id\s*)integer/$1SERIAL/i;
65 12         48 }
66              
67 12 50       34 return $query;
68 0         0 }
69              
70             #pod =head2 determine_version
71 12         91 #pod
72             #pod This attempts to determine the version of the database schema to which the
73             #pod given database conforms. All recent schemata store their version number; for
74             #pod older versions, some simple table attributes are checked.
75             #pod
76             #pod =cut
77              
78             my ($class, $query) = @_;
79             return scalar(my @columns = $class->dbh->selectrow_array($query));
80             }
81              
82             my ($class) = @_;
83 0     0   0  
84 0         0 my ($version) = $class->dbh->selectrow_array("SELECT schema_version FROM rubric");
85              
86             if ($version) {
87             if ($version == 6) {
88 3     3 1 8555 # some schemata are broken, and claim 6 on 7
89             eval {
90 3         9 $class->dbh->selectall_array("SELECT verification_code FROM users");
91             };
92 3 50       306 if ($@) {
93 3 50       8 warn "your db schema label is incorrect; run rubric db -u"; return 7;
94             } else {
95 0         0 return 6;
96 0         0 }
97             } else {
98 0 0       0 return $version;
99 0         0 }
  0         0  
100             }
101 0         0  
102             # v4 added body column;
103             return 4 if $class->_columns("SELECT * FROM entries LIMIT 1") == 8;
104 3         16  
105             # v3 added email and validation_code;
106             return 3 if $class->_columns("SELECT * FROM users LIMIT 1") == 4;
107              
108             # v2 added md5 column;
109 0 0       0 return 2 if $class->_columns("SELECT * FROM links LIMIT 1") == 3;
110              
111             return 1 if $class->_columns("SELECT * FROM links LIMIT 1") == 2;
112 0 0       0  
113             return;
114             }
115 0 0       0  
116             #pod =head2 determine_db_type
117 0 0       0 #pod
118             #pod Returns the type of db being used, based on the DSN's DBD driver.
119 0         0 #pod SQLite and Pg support only right now.
120             #pod
121             #pod =cut
122              
123             my ($class) = @_;
124              
125             Rubric::Config->dsn =~ /dbi:([^:]+):/;
126              
127             my $db_type = $1;
128              
129             return $db_type;
130 12     12 1 32 }
131              
132 12         72 #pod =head2 update_schema
133             #pod
134 12         48 #pod This method will try to upgrade the database to the most recent schema. It's
135             #pod sort of ugly, but it works...
136 12         31 #pod
137             #pod =cut
138              
139             my %from;
140              
141             # from 1 to 2
142             # add md5 sum to links table
143              
144             $from{1} = sub {
145             require Digest::MD5;
146             $dbh->func('md5hex', 1, \&Digest::MD5::md5_hex, 'create_function');
147              
148             my $sql = <<'END_SQL';
149             CREATE TABLE new_links (
150             id INTEGER PRIMARY KEY,
151             uri varchar UNIQUE NOT NULL,
152             md5 varchar NOT NULL
153             );
154              
155             INSERT INTO new_links
156             SELECT id, uri, md5hex(uri) FROM links;
157              
158             DROP TABLE links;
159              
160             CREATE TABLE links (
161             id INTEGER PRIMARY KEY,
162             uri varchar UNIQUE NOT NULL,
163             md5 varchar NOT NULL
164             );
165              
166             INSERT INTO links
167             SELECT id, uri, md5 FROM new_links;
168              
169             DROP TABLE new_links;
170             END_SQL
171              
172             $dbh->do($_) for split /\n\n/, $sql;
173             };
174              
175             # from 2 to 3
176             # add email and validation_code
177             # fill in email with garbage data
178              
179             $from{2} = sub {
180             my $sql = <<'END_SQL';
181             CREATE TABLE new_users (
182             username PRIMARY KEY,
183             password NOT NULL,
184             email NOT NULL,
185             validation_code
186             );
187              
188             INSERT INTO new_users
189             SELECT *, 'user@example.com', NULL FROM users;
190              
191             DROP TABLE users;
192              
193             CREATE TABLE users (
194             username PRIMARY KEY,
195             password NOT NULL,
196             email NOT NULL,
197             validation_code
198             );
199              
200             INSERT INTO users
201             SELECT * FROM new_users;
202              
203             DROP TABLE new_users;
204             END_SQL
205              
206             $dbh->do($_) for split /\n\n/, $sql;
207             };
208              
209             # from 3 to 4
210             # link becomes null-ok
211             # add body column
212              
213             $from{3} = sub {
214             my $sql = <<END_SQL;
215             CREATE TABLE new_entries (
216             id INTEGER PRIMARY KEY,
217             link integer,
218             user varchar NOT NULL,
219             title varchar NOT NULL,
220             created NOT NULL,
221             modified NOT NULL,
222             description varchar,
223             body TEXT
224             );
225              
226             INSERT INTO new_entries
227             SELECT *, NULL FROM entries;
228              
229             DROP TABLE entries;
230              
231             CREATE TABLE entries (
232             id INTEGER PRIMARY KEY,
233             link integer,
234             user varchar NOT NULL,
235             title varchar NOT NULL,
236             created NOT NULL,
237             modified NOT NULL,
238             description varchar,
239             body TEXT
240             );
241              
242             INSERT INTO entries
243             SELECT * FROM new_entries;
244              
245             DROP TABLE new_entries;
246             END_SQL
247              
248             $dbh->do($_) for split /\n\n/, $sql;
249             };
250              
251             # from 4 to 5
252             # add rubric table and schema number
253              
254             $from{4} = sub {
255             my $sql = <<END_SQL;
256             CREATE TABLE rubric (
257             schema_version NOT NULL
258             );
259              
260             INSERT INTO rubric (schema_version) VALUES (5);
261             END_SQL
262              
263             $dbh->do($_) for split /\n\n/, $sql;
264             };
265              
266             # from 5 to 6
267             # add "created" column to users
268              
269             $from{5} = sub {
270             my $sql = <<'END_SQL';
271             CREATE TABLE new_users (
272             username PRIMARY KEY,
273             password NOT NULL,
274             email NOT NULL,
275             created NOT NULL,
276             validation_code
277             );
278              
279             INSERT INTO new_users
280             SELECT username, password, email, 0, validation_code
281             FROM users;
282              
283             DROP TABLE users;
284              
285             CREATE TABLE users (
286             username PRIMARY KEY,
287             password NOT NULL,
288             email NOT NULL,
289             created NOT NULL,
290             validation_code
291             );
292              
293             INSERT INTO users
294             SELECT * FROM new_users;
295              
296             DROP TABLE new_users;
297              
298             UPDATE rubric SET schema_version = 6;
299             END_SQL
300              
301             $dbh->do($_) for split /\n\n/, $sql;
302             };
303              
304             # from 6 to 7
305             # validation_code is now verification_code
306              
307             $from{6} = sub {
308             my $sql = <<'END_SQL';
309             CREATE TABLE new_users (
310             username PRIMARY KEY,
311             password NOT NULL,
312             email NOT NULL,
313             created NOT NULL,
314             verification_code
315             );
316              
317             INSERT INTO new_users
318             SELECT username, password, email, created, validation_code
319             FROM users;
320              
321             DROP TABLE users;
322              
323             CREATE TABLE users (
324             username PRIMARY KEY,
325             password NOT NULL,
326             email NOT NULL,
327             created NOT NULL,
328             verification_code
329             );
330              
331             INSERT INTO users
332             SELECT * FROM new_users;
333              
334             DROP TABLE new_users;
335              
336             UPDATE rubric SET schema_version = 7;
337             END_SQL
338              
339             $dbh->do($_) for split /\n\n/, $sql;
340             };
341              
342             # from 7 to 8
343             # add reset_code
344              
345             $from{7} = sub {
346             my $sql = <<'END_SQL';
347             CREATE TABLE new_users (
348             username PRIMARY KEY,
349             password NOT NULL,
350             email NOT NULL,
351             created NOT NULL,
352             verification_code,
353             reset_code
354             );
355              
356             INSERT INTO new_users
357             SELECT username, password, email, created, verification_code, NULL
358             FROM users;
359              
360             DROP TABLE users;
361              
362             CREATE TABLE users (
363             username PRIMARY KEY,
364             password NOT NULL,
365             email NOT NULL,
366             created NOT NULL,
367             verification_code,
368             reset_code
369             );
370              
371             INSERT INTO users
372             SELECT * FROM new_users;
373              
374             DROP TABLE new_users;
375              
376             UPDATE rubric SET schema_version = 8;
377             END_SQL
378              
379             $dbh->do($_) for split /\n\n/, $sql;
380             };
381              
382             $from{8} = sub {
383             my $sql = <<'END_SQL';
384             CREATE TABLE new_entrytags (
385             id INTEGER PRIMARY KEY,
386             entry NOT NULL,
387             tag NOT NULL,
388             tag_value,
389             UNIQUE(entry, tag)
390             );
391              
392             INSERT INTO new_entrytags
393             SELECT id, entry, tag, NULL
394             FROM entrytags;
395              
396             DROP TABLE entrytags;
397              
398             CREATE TABLE entrytags (
399             id INTEGER PRIMARY KEY,
400             entry NOT NULL,
401             tag NOT NULL,
402             tag_value,
403             UNIQUE(entry, tag)
404             );
405              
406             INSERT INTO entrytags
407             SELECT * FROM new_entrytags;
408              
409             DROP TABLE new_entrytags;
410              
411             UPDATE rubric SET schema_version = 9;
412             END_SQL
413              
414             $dbh->do($_) for split /\n\n/, $sql;
415             };
416              
417             $from{9} = sub {
418             my $sql = <<'END_SQL';
419             CREATE TABLE new_users (
420             username varchar PRIMARY KEY,
421             password varchar NOT NULL,
422             email varchar NOT NULL,
423             created integer NOT NULL,
424             verification_code varchar,
425             reset_code varchar
426             );
427              
428             INSERT INTO new_users
429             SELECT username, password, email, created, verification_code, reset_code
430             FROM users;
431              
432             DROP TABLE users;
433              
434             CREATE TABLE users (
435             username varchar PRIMARY KEY,
436             password varchar NOT NULL,
437             email varchar NOT NULL,
438             created integer NOT NULL,
439             verification_code varchar,
440             reset_code varchar
441             );
442              
443             INSERT INTO users
444             SELECT username, password, email, created, verification_code, reset_code
445             FROM new_users;
446              
447             DROP TABLE new_users;
448              
449             CREATE TABLE new_entries (
450             id integer PRIMARY KEY,
451             link integer,
452             user varchar NOT NULL,
453             title varchar NOT NULL,
454             created integer NOT NULL,
455             modified integer NOT NULL,
456             description varchar,
457             body TEXT
458             );
459              
460             INSERT INTO new_entries
461             SELECT id, link, user, title, created, modified, description, body
462             FROM entries;
463              
464             DROP TABLE entries;
465              
466             CREATE TABLE entries (
467             id integer PRIMARY KEY,
468             link integer,
469             user varchar NOT NULL,
470             title varchar NOT NULL,
471             created integer NOT NULL,
472             modified integer NOT NULL,
473             description varchar,
474             body TEXT
475             );
476              
477             INSERT INTO entries
478             SELECT id, link, user, title, created, modified, description, body
479             FROM new_entries;
480              
481             DROP TABLE new_entries;
482              
483             CREATE TABLE new_entrytags (
484             id INTEGER PRIMARY KEY,
485             entry integer NOT NULL,
486             tag varchar NOT NULL,
487             tag_value varchar,
488             UNIQUE(entry, tag)
489             );
490              
491             INSERT INTO new_entrytags
492             SELECT id, entry, tag, tag_value
493             FROM entrytags;
494              
495             DROP TABLE entrytags;
496              
497             CREATE TABLE entrytags (
498             id INTEGER PRIMARY KEY,
499             entry integer NOT NULL,
500             tag varchar NOT NULL,
501             tag_value varchar,
502             UNIQUE(entry, tag)
503             );
504              
505             INSERT INTO entrytags
506             SELECT id, entry, tag, tag_value
507             FROM new_entrytags;
508              
509             DROP TABLE new_entrytags;
510              
511             DROP TABLE rubric;
512              
513             CREATE TABLE rubric (
514             schema_version integer NOT NULL
515             );
516              
517             INSERT INTO rubric (schema_version) VALUES (10);
518             END_SQL
519              
520             $dbh->do($_) for split /\n\n/, $sql;
521             };
522              
523             $from{10} = sub {
524             my $sql = <<'END_SQL';
525             CREATE TABLE new_entries (
526             id integer PRIMARY KEY,
527             link integer,
528             username varchar NOT NULL,
529             title varchar NOT NULL,
530             created integer NOT NULL,
531             modified integer NOT NULL,
532             description varchar,
533             body TEXT
534             );
535              
536             INSERT INTO new_entries (id, link, username, title, created, modified, description, body)
537             SELECT id, link, user, title, created, modified, description, body
538             FROM entries;
539              
540             DROP TABLE entries;
541              
542             CREATE TABLE entries (
543             id integer PRIMARY KEY,
544             link integer,
545             username varchar NOT NULL,
546             title varchar NOT NULL,
547             created integer NOT NULL,
548             modified integer NOT NULL,
549             description varchar,
550             body TEXT
551             );
552              
553             INSERT INTO entries
554             SELECT id, link, username, title, created, modified, description, body
555             FROM new_entries;
556              
557             DROP TABLE new_entries;
558              
559             UPDATE rubric SET schema_version = 11;
560             END_SQL
561              
562             $dbh->do($_) for split /\n\n/, $sql;
563             };
564              
565             $from{11} = undef;
566              
567             my ($class) = @_;
568              
569             while ($_ = $class->determine_version) {
570             die "no update path from schema version $_" unless exists $from{$_};
571             last unless defined $from{$_};
572             print "updating from version $_...\n";
573             $from{$_}->();
574             }
575 1     1 1 3 return $class->determine_version;
576             }
577 1         5  
578 1 50       5 1;
579 1 50       5  
580 0         0 =pod
581 0         0  
582             =encoding UTF-8
583 1         3  
584             =head1 NAME
585              
586             Rubric::DBI::Setup - db initialization routines
587              
588             =head1 VERSION
589              
590             version 0.157
591              
592             =head1 SYNOPSIS
593              
594             use strict;
595             use warnings;
596              
597             use Rubric::DBI::Setup;
598             Rubric::DBI::Setup->setup_tables;
599              
600             =head1 DESCRIPTION
601              
602             =head1 PERL VERSION
603              
604             This code is effectively abandonware. Although releases will sometimes be made
605             to update contact info or to fix packaging flaws, bug reports will mostly be
606             ignored. Feature requests are even more likely to be ignored. (If someone
607             takes up maintenance of this code, they will presumably remove this notice.)
608             This means that whatever version of perl is currently required is unlikely to
609             change -- but also that it might change at any new maintainer's whim.
610              
611             =head1 METHODS
612              
613             =head2 dbh
614              
615             This method returns a connection to the Rubric database.
616              
617             =head2 setup_tables
618              
619             This method builds the tables in the database, if needed.
620              
621             =head2 specialize_sql
622              
623             attempts to convert the given sql syntax to the given DBD Driver's
624              
625             =head2 determine_version
626              
627             This attempts to determine the version of the database schema to which the
628             given database conforms. All recent schemata store their version number; for
629             older versions, some simple table attributes are checked.
630              
631             =head2 determine_db_type
632              
633             Returns the type of db being used, based on the DSN's DBD driver.
634             SQLite and Pg support only right now.
635              
636             =head2 update_schema
637              
638             This method will try to upgrade the database to the most recent schema. It's
639             sort of ugly, but it works...
640              
641             =head1 AUTHOR
642              
643             Ricardo SIGNES <rjbs@semiotic.systems>
644              
645             =head1 COPYRIGHT AND LICENSE
646              
647             This software is copyright (c) 2004 by Ricardo SIGNES.
648              
649             This is free software; you can redistribute it and/or modify it under
650             the same terms as the Perl 5 programming language system itself.
651              
652             =cut
653              
654             CREATE TABLE links (
655             id integer PRIMARY KEY,
656             uri varchar UNIQUE NOT NULL,
657             md5 varchar NOT NULL
658             );
659              
660             CREATE TABLE users (
661             username varchar PRIMARY KEY,
662             password varchar NOT NULL,
663             email varchar NOT NULL,
664             created integer NOT NULL,
665             verification_code varchar,
666             reset_code varchar
667             );
668              
669             CREATE TABLE entries (
670             id integer PRIMARY KEY,
671             link integer,
672             username varchar NOT NULL,
673             title varchar NOT NULL,
674             created integer NOT NULL,
675             modified integer NOT NULL,
676             description varchar,
677             body TEXT
678             );
679              
680             CREATE TABLE entrytags (
681             id INTEGER PRIMARY KEY,
682             entry integer NOT NULL,
683             tag varchar NOT NULL,
684             tag_value varchar,
685             UNIQUE(entry, tag)
686             );
687              
688             CREATE TABLE rubric (
689             schema_version integer NOT NULL
690             );
691              
692             INSERT INTO rubric (schema_version) VALUES (11);