File Coverage

blib/lib/File/Catalog/DB.pm
Criterion Covered Total %
statement 17 136 12.5
branch 0 22 0.0
condition n/a
subroutine 6 24 25.0
pod 17 17 100.0
total 40 199 20.1


line stmt bran cond sub pod time code
1             # base de donnees du catalogage
2              
3             package File::Catalog::DB;
4              
5 1     1   13 use 5.010;
  1         2  
6 1     1   4 use warnings;
  1         1  
  1         18  
7 1     1   3 use strict;
  1         1  
  1         14  
8 1     1   1162 use DBI;
  1         11631  
  1         57  
9 1     1   8 use Log::Log4perl qw(:easy);
  1         1  
  1         8  
10 1     1   453 use Data::Dumper qw(Dumper);
  1         1  
  1         1218  
11              
12             =head1 NAME
13              
14             File::Catalog::DB - The great new File::Catalog::DB!
15              
16             =head1 VERSION
17              
18             Version 0.003
19              
20             =cut
21              
22             our $VERSION = 0.003;
23              
24             =head1 SYNOPSIS
25              
26             Quick summary of what the module does.
27              
28             Perhaps a little code snippet.
29              
30             use File::Catalog;
31              
32             my $foo = File::Catalog->new();
33             ...
34              
35             =head1 EXPORT
36              
37             A list of functions that can be exported. You can delete this section
38             if you don't export anything, such as for a purely object-oriented module.
39              
40             =cut
41              
42             =head1 SUBROUTINES/METHODS
43              
44             =head2 connect
45              
46             =cut
47              
48             # creation/connection/construction/preparation
49             sub connect {
50 0     0 1   my ($class, $nomfic, $extension) = @_;
51 0           my $self = {};
52 0           bless $self, $class;
53              
54             # memo nouvelle base ou pas
55 0           $self->{new} = !-f $nomfic;
56              
57             # connection
58 0 0         $self->{dbh} = DBI->connect("dbi:SQLite:dbname=$nomfic", "", "")
59             or die "Connection impossible a la base de donnees $nomfic !\n $! \n $@\n$DBI::errstr";
60              
61             # creation des tables si nouvelle base
62 0 0         if ($self->{new}) {
63              
64             # creation tables BD
65 0           $self->{dbh}->do("CREATE TABLE Fichier (repfic TEXT PRIMARY KEY, rep TEXT, fic TEXT, volinode TEXT)");
66             $self->{dbh}->do(
67 0           "CREATE TABLE Inode (
68             volinode TEXT PRIMARY KEY, volume TEXT, inode INTEGER, mode INTEGER, size INTEGER,
69             atime INTEGER, mtime INTEGER, ctime INTEGER, archive INTEGER, md5sum TEXT)"
70             );
71             }
72              
73             # preparation des requetes
74 0           $self->definir_requetes();
75              
76             # initialiser les colonnes complementaires
77 0           $self->initialiser_extension($extension);
78              
79             # preparation des requetes
80 0           $self->preparer_requetes();
81              
82             # retour
83 0           return $self;
84             }
85              
86             =head2 initialiser_extension
87              
88             =cut
89              
90             # prise en compte des colonnes complementaires
91             sub initialiser_extension {
92 0     0 1   my ($self, $extension) = @_;
93              
94 0 0         if (defined $extension) {
95 0           DEBUG "extension BD definie";
96              
97             #ZZZ tester le contenu de extension : list, columns, trigger
98 0           my @liste = @{ $extension->{list} };
  0            
99 0           my $types = $extension->{columns};
100              
101             # pour chaque element de la liste
102 0           foreach my $col (@liste) {
103 0           DEBUG "ajout colonne $col";
104              
105             # ajouter une colonne
106 0 0         my $type = (exists $types->{$col}) ? $types->{$col} : 'TEXT';
107             $self->{dbh}->do("ALTER TABLE Fichier ADD COLUMN $col $type")
108 0 0         if $self->{new};
109              
110             # maj requete insertF
111 0           $self->{requete}->{insertF} =~ s/\?/\?, \?/;
112             }
113              
114 0 0         if ($self->{new}) {
115              
116             # ajout d'un index
117 0           my $nom_index = "idx_" . join "_", @liste;
118 0           my $liste_index = join ",", @liste;
119 0           $self->{dbh}->do("CREATE INDEX $nom_index ON Fichier ($liste_index)");
120             }
121              
122             # memoriser le trigger associe
123 0           $self->{trigger} = $extension->{trigger};
124              
125             # memoriser les requetes a preparer
126 0           my $requetes = $extension->{requests};
127 0           foreach my $requete (keys %$requetes) {
128 0           $self->{requete}->{$requete} = $requetes->{$requete};
129             }
130             }
131             else {
132 0           DEBUG "pas d'extension BD";
133              
134             # trigger par defaut
135             $self->{trigger} = sub {
136 0     0     return (1); # 1 pour ok tout va bien
137 0           };
138             }
139             }
140              
141             =head2 handler
142              
143             =cut
144              
145             # acces handler
146             sub handler {
147 0     0 1   my ($self) = @_;
148 0           return $self->{dbh};
149             }
150              
151             =head2 disconnect
152              
153             =cut
154              
155             # deconnection
156             sub disconnect {
157 0     0 1   my ($self) = @_;
158 0           $self->{dbh}->disconnect;
159             }
160              
161             =head2 definir_requetes
162              
163             =cut
164              
165             # definition des requetes
166             sub definir_requetes {
167 0     0 1   my ($self) = @_;
168 0           my $db = $self->{dbh};
169              
170 0           $self->{requete}->{insertF} = "INSERT INTO Fichier VALUES (?, ?, ?, ?)";
171 0           $self->{requete}->{updateF} = "UPDATE Fichier SET volinode = ? WHERE repfic = ?";
172 0           $self->{requete}->{deleteF} = "DELETE from Fichier WHERE repfic = ?";
173              
174 0           $self->{requete}->{insertI} = "INSERT INTO Inode VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
175             $self->{requete}->{updateI} =
176 0           "UPDATE Inode SET mode = ?, size = ?, atime = ?, mtime = ?, ctime = ?, archive = ?, md5sum = ? WHERE volinode = ?";
177 0           $self->{requete}->{deleteI} = "DELETE from Inode WHERE volinode = ?";
178              
179 0           $self->{requete}->{lister_volumes} = "SELECT DISTINCT volume FROM Inode ORDER BY volume";
180              
181             $self->{requete}->{lister_archives} =
182 0           "SELECT I.md5sum, F.repfic FROM Fichier AS F LEFT JOIN Inode AS I ON F.volinode = I.volinode
183             WHERE I.archive = 1
184             ORDER BY I.md5sum";
185              
186             $self->{requete}->{lister_doublons} =
187 0           "SELECT I.md5sum, F.repfic FROM Fichier F LEFT JOIN Inode I ON F.volinode = I.volinode
188             WHERE I.md5sum IN (SELECT md5sum FROM (SELECT md5sum, count(*) AS nb FROM Inode GROUP BY md5sum HAVING nb > 1))
189             AND F.repfic glob ?
190             ORDER BY I.md5sum, I.mtime, F.repfic";
191              
192             $self->{requete}->{lister_doublons_volume} =
193 0           "SELECT F.repfic FROM Fichier F LEFT JOIN Inode I ON F.volinode = I.volinode
194             WHERE I.volume = ?
195             AND I.md5sum IN (SELECT DISTINCT md5sum FROM Inode WHERE volume = ?)
196             ORDER BY I.mtime, F.repfic";
197              
198             $self->{requete}->{lister_fichiers} =
199 0           "SELECT I.md5sum, I.archive, F.repfic FROM Fichier AS F LEFT JOIN Inode AS I ON F.volinode = I.volinode
200             WHERE F.repfic glob ?
201             ORDER BY F.repfic";
202              
203 0           $self->{requete}->{lister_repertoires} = "SELECT DISTINCT F.rep, COUNT(*) FROM Fichier AS F
204             WHERE F.rep glob ?
205             GROUP BY F.rep
206             ORDER BY F.rep";
207              
208 0           $self->{requete}->{lire_volinode} = "SELECT * FROM Inode WHERE volinode = ?";
209              
210 0           $self->{requete}->{lister_volinodes} = "SELECT volinode FROM Fichier WHERE repfic = ?";
211              
212             $self->{requete}->{lire_volinode_archive} =
213 0           "SELECT F.volinode, I.archive FROM Fichier F LEFT JOIN Inode I ON F.volinode = I.volinode
214             WHERE F.repfic = ?";
215              
216 0           $self->{requete}->{nb_occurrences_volinode} = "SELECT count(*) FROM Fichier WHERE volinode = ?";
217              
218 0           $self->{requete}->{nb_occurrences_md5sum} = "SELECT count(*) FROM Inode WHERE md5sum = ?";
219             }
220              
221             =head2 preparer_requetes
222              
223             =cut
224              
225             # preparation des requetes
226             sub preparer_requetes {
227 0     0 1   my ($self) = @_;
228 0           my $db = $self->{dbh};
229              
230 0           foreach my $req (keys %{ $self->{requete} }) {
  0            
231 0           DEBUG $req . ": " . $self->{requete}->{$req};
232 0           $self->{$req} = $db->prepare($self->{requete}->{$req});
233             }
234             }
235              
236             =head2 execute
237              
238             =cut
239              
240             # acces aux requetes preparees
241             sub execute {
242 0     0 1   my ($self, $requete, @params) = @_;
243             $self->{$requete}->execute(@params)
244 0 0         or $self->{logger}->error("Pb execution requete '" . $requete . "'");
245 0           return $self->{$requete};
246             }
247              
248             #=== acces base de donnees ===
249              
250             =head2 lire_volinode_archive
251              
252             =cut
253              
254             # volinode
255             sub lire_volinode_archive {
256 0     0 1   my ($self, $repfic) = @_;
257              
258 0           my $row = $self->execute('lire_volinode_archive', $repfic)->fetchrow_arrayref();
259 0           $self->{lire_volinode_archive}->finish();
260              
261 0           return $row;
262             }
263              
264             =head2 nb_occurrences_volinode
265              
266             =cut
267              
268             # volinode
269             sub nb_occurrences_volinode {
270 0     0 1   my ($self, $volinode) = @_;
271              
272 0           my $row = $self->execute('nb_occurrences_volinode', $volinode)->fetchrow_arrayref();
273 0           $self->{nb_occurrences_volinode}->finish();
274              
275 0           return $row->[0];
276             }
277              
278             =head2 nb_occurrences_md5sum
279              
280             =cut
281              
282             # md5sum
283             sub nb_occurrences_md5sum {
284 0     0 1   my ($self, $md5sum) = @_;
285              
286 0           my $row = $self->execute('nb_occurrences_md5sum', $md5sum)->fetchrow_arrayref();
287 0           $self->{nb_occurrences_md5sum}->finish();
288              
289 0           return $row->[0];
290             }
291              
292             =head2 lister_volumes
293              
294             =cut
295              
296             # volumes
297             sub lister_volumes {
298 0     0 1   my ($self) = @_;
299              
300 0           my $rows = $self->execute('lister_volumes')->fetchall_arrayref();
301              
302 0           return map { join " ", @$_ } @$rows;
  0            
303             }
304              
305             =head2 lister_archives
306              
307             =cut
308              
309             # archives
310             sub lister_archives {
311 0     0 1   my ($self) = @_;
312 0           my %cpt;
313              
314 0           my $rows = $self->execute('lister_archives')->fetchall_arrayref();
315              
316 0           return map { $_->[0] . " [" . $cpt{ $_->[0] }++ . "] " . $_->[1] } @$rows;
  0            
317             }
318              
319             =head2 lister_doublons
320              
321             =cut
322              
323             # doublons
324             sub lister_doublons {
325 0     0 1   my ($self, $filtre) = @_;
326 0           my %cpt;
327              
328 0 0         $filtre = '*' unless defined $filtre;
329 0           my $rows = $self->execute('lister_doublons', $filtre)->fetchall_arrayref();
330              
331 0           return map { $_->[0] . " [" . $cpt{ $_->[0] }++ . "] " . $_->[1] } @$rows;
  0            
332             }
333              
334             =head2 lister_doublons_volumes
335              
336             =cut
337              
338             # doublons
339             sub lister_doublons_volumes {
340 0     0 1   my ($self, $volref, $voldbl) = @_;
341              
342 0           my $rows = $self->execute('lister_doublons_volumes', $voldbl, $volref)->fetchall_arrayref();
343              
344 0           return map { $_->[0] } @$rows;
  0            
345             }
346              
347             =head2 lister_fichiers
348              
349             =cut
350              
351             # fichiers
352             # glob gere les wildcards * et ?
353             sub lister_fichiers {
354 0     0 1   my ($self, $filtre) = @_;
355              
356 0 0         $filtre = '*' unless defined $filtre;
357 0           my $rows = $self->execute('lister_fichiers', $filtre)->fetchall_arrayref();
358              
359 0           return $rows;
360             }
361              
362             =head2 lister_repertoires
363              
364             =cut
365              
366             # fichiers
367             # glob gere les wildcards * et ?
368             sub lister_repertoires {
369 0     0 1   my ($self, $filtre) = @_;
370              
371 0 0         $filtre = '*' unless defined $filtre;
372 0           my $rows = $self->execute('lister_repertoires', $filtre)->fetchall_arrayref();
373              
374 0           return map { $_->[1] . "\t" . $_->[0] } @$rows;
  0            
375             }
376              
377             =head2 afficher
378              
379             =cut
380              
381             # affichage
382             sub afficher {
383 0     0 1   my ($self) = @_;
384 0           my $db = $self->{dbh};
385              
386 0           my $txt;
387 0           $txt .= "=== Fichier ===\n";
388 0           my $rowsF = $db->selectall_arrayref("SELECT * FROM Fichier ORDER BY repfic");
389 0           foreach my $row (@$rowsF) {
390 0           $txt += join(", ", @$row) . "\n";
391             }
392 0           $txt .= "=== Inode ===\n";
393 0           my $rowsI = $db->selectall_arrayref("SELECT * FROM Inode ORDER BY volinode");
394 0           foreach my $row (@$rowsI) {
395 0 0         @$row[$#$row] = "{}" unless @$row[$#$row];
396 0           $txt += join(", ", @$row) . "\n";
397             }
398              
399 0           return $txt;
400             }
401              
402             =head1 AUTHOR
403              
404             Patrick Hingrez, C<< >>
405              
406             =head1 BUGS
407              
408             Please report any bugs or feature requests to C, or through
409             the web interface at L. I will be notified, and then you'll
410             automatically be notified of progress on your bug as I make changes.
411              
412              
413              
414              
415             =head1 SUPPORT
416              
417             You can find documentation for this module with the perldoc command.
418              
419             perldoc File::Catalog
420              
421              
422             You can also look for information at:
423              
424             =over 4
425              
426             =item * RT: CPAN's request tracker (report bugs here)
427              
428             L
429              
430             =item * AnnoCPAN: Annotated CPAN documentation
431              
432             L
433              
434             =item * CPAN Ratings
435              
436             L
437              
438             =item * Search CPAN
439              
440             L
441              
442             =back
443              
444              
445             =head1 ACKNOWLEDGEMENTS
446              
447              
448             =head1 LICENSE AND COPYRIGHT
449              
450             Copyright 2015 Patrick Hingrez.
451              
452             This program is free software; you can redistribute it and/or modify it
453             under the terms of the the Artistic License (2.0). You may obtain a
454             copy of the full license at:
455              
456             L
457              
458             Any use, modification, and distribution of the Standard or Modified
459             Versions is governed by this Artistic License. By using, modifying or
460             distributing the Package, you accept this license. Do not use, modify,
461             or distribute the Package, if you do not accept this license.
462              
463             If your Modified Version has been derived from a Modified Version made
464             by someone other than you, you are nevertheless required to ensure that
465             your Modified Version complies with the requirements of this license.
466              
467             This license does not grant you the right to use any trademark, service
468             mark, tradename, or logo of the Copyright Holder.
469              
470             This license includes the non-exclusive, worldwide, free-of-charge
471             patent license to make, have made, use, offer to sell, sell, import and
472             otherwise transfer the Package with respect to any patent claims
473             licensable by the Copyright Holder that are necessarily infringed by the
474             Package. If you institute patent litigation (including a cross-claim or
475             counterclaim) against any party alleging that the Package constitutes
476             direct or contributory patent infringement, then this Artistic License
477             to you shall terminate on the date that such litigation is filed.
478              
479             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
480             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
481             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
482             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
483             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
484             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
485             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
486             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
487              
488              
489             =cut
490              
491             1; # End of File::Catalog::DB