File Coverage

blib/lib/Text/CSV/SQLhelper.pm
Criterion Covered Total %
statement 6 173 3.4
branch 0 92 0.0
condition 0 12 0.0
subroutine 2 7 28.5
pod 5 5 100.0
total 13 289 4.5


line stmt bran cond sub pod time code
1             package Text::CSV::SQLhelper;
2              
3 1     1   20500 use warnings;
  1         3  
  1         31  
4 1     1   5 use strict;
  1         2  
  1         1682  
5              
6             =head1 NAME
7              
8             Text::CSV::SQLhelper - Processes a CSV file and tries to figure out
9              
10             =head1 VERSION
11              
12             Version 0.0.0
13              
14             =cut
15              
16             our $VERSION = '0.0.0';
17              
18              
19             =head1 SYNOPSIS
20              
21              
22              
23             =head1 METHODS
24              
25             =head2 new
26              
27             =head3 args hash
28              
29             =head4 csv
30              
31             This is the text CSV object.
32              
33             =head4 defaultAllowNull
34              
35             If no null is found,
36              
37             It defaults to false.
38              
39             =cut
40              
41             sub new{
42 0     0 1   my %args;
43 0 0         if(defined($_[1])){
44 0           %args= %{$_[1]};
  0            
45             }
46 0           my $method='new';
47              
48 0           my $self={
49             error=>undef,
50             perror=>undef,
51             errorString=>undef,
52             module=>'Text-CSV-SQLhelper',
53             };
54 0           bless $self;
55              
56 0 0         if (!defined( $args{csv} )) {
57 0           $self->{error}=1;
58 0           $self->{perror}=1;
59 0           $self->{errorString}='No Text::CSV object passed';
60 0           warn( $self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString} );
61 0           return $self;
62             }
63              
64 0 0         if (ref( $args{csv} ) ne 'Text::CSV') {
65 0           $self->{error}=1;
66 0           $self->{perror}=1;
67 0           $self->{errorString}='No Text::CSV object passed';
68 0           warn( $self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString} );
69 0           return $self;
70             }
71              
72 0 0         if (!defined($args{defaultAllowNull})) {
73 0           $args{defaultAllowNull}=0;
74             }
75              
76 0           $self->{csv}=$args{csv};
77 0           $self->{allownull}=$args{defaultAllowNull};
78              
79 0           return $self;
80             }
81              
82             =head2
83              
84             =head2 error
85              
86             Returns the current error code and true if there is an error.
87              
88             If there is no error, undef is returned.
89              
90             my $error=$foo->error;
91             if($error){
92             print 'error code: '.$error."\n";
93             }
94              
95             =cut
96              
97             sub error{
98 0     0 1   return $_[0]->{error};
99             }
100              
101             =head2 errorString
102              
103             Returns the error string if there is one. If there is not,
104             it will return ''.
105              
106             my $error=$foo->error;
107             if($error){
108             print 'error code:'.$error.': '.$foo->errorString."\n";
109             }
110              
111             =cut
112              
113             sub errorString{
114 0     0 1   return $_[0]->{errorString};
115             }
116              
117             =head2 processFile
118              
119             This processes the specified file.
120              
121             Two arguements are required. The first one is the file to read and the
122             second one is a boolean specifying if the top line should be skipped
123             or not.
124              
125             The returned value is a array.
126              
127             =head3 returned array
128              
129             =head4 allownull
130              
131             Wether or not a column can have a null value.
132              
133             This defaults to false.
134              
135             =head4 min
136              
137             This is the smallest value found. In regards to strings,
138             it represents number of characters in the shortest string.
139              
140             =head4 max
141              
142             This is the largest value found. In regards to strings,
143             it represents number of characters in the longest string.
144              
145             =head4 sql
146              
147             This is a SQL description for the column.
148              
149             =head4 type
150              
151             This is the data type of the column.
152              
153             The possible values are 'float', 'int', and 'string'.
154              
155              
156             #process the file, including the top line
157             my @columns=$foo->processFile($file);
158             if($foo->error){
159             print 'error code:'.$foo->error.': '.$foo->errorString."\n";
160             }
161              
162             #process the file, skipping the top line
163             my @columns=$foo->processFile($file, 1);
164             if($foo->error){
165             print 'error code:'.$foo->error.': '.$foo->errorString."\n";
166             }
167              
168              
169             =cut
170              
171             sub processFile{
172 0     0 1   my $self=$_[0];
173 0           my $file=$_[1];
174 0           my $removetop=$_[2];
175 0           my $method='processfile';
176              
177 0           $self->errorblank;
178 0 0         if ($self->error) {
179 0           warn($self->{module}.' '.$method.': failed to blank the previous error');
180 0           return undef;
181             }
182              
183 0 0         if (!defined($file)) {
184 0           $self->{error}=2;
185 0           $self->{errorString}='No file specified';
186 0           warn( $self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString} );
187 0           return undef;
188             }
189              
190             #read the file
191 0           my $fh;
192 0 0         if (!open($fh, "<:encoding(utf8)", $file)) {
193 0           $self->{error}=3;
194 0           $self->{errorString}='Failed to open the file, "'.$file.'",';
195 0           warn( $self->{module}.' '.$method.':'.$self->{error}.': '.$self->{errorString} );
196 0           return undef;
197             }
198              
199             #what will be returned
200 0           my @columns;
201              
202             #remove the top if asked to
203 0 0         if ($removetop) {
204 0           my @top=@{$self->{csv}->getline ($fh)};
  0            
205             }
206              
207             #processes each row
208 0           my @row;
209 0           my $continueloop=1;
210             #fetches the new row and we do get it, save it as a array and if we don't stop this loop
211 0           my $newrow=$self->{csv}->getline ($fh);
212 0 0         if (defined($newrow->[0])) {
213 0           @row = @{$newrow};
  0            
214             }else {
215 0           $continueloop=0;
216             }
217 0           while ($continueloop) {
218             #processes each row
219 0           my $int=0;
220 0           while ($int <= $#row) {
221 0           my %rowinfo;
222 0           my $matched=0;
223              
224             #handles it if this item is undefined
225 0 0         if (!defined($row[$int])) {
226 0 0         if (!defined( $columns[$int] )) {
227 0           $rowinfo{allownull}=1;
228 0           $rowinfo{min}=0;
229 0           $rowinfo{max}=0;
230 0           $columns[$int]=\%rowinfo;
231             }else {
232 0           $columns[$int]{allownull}=1;
233             }
234 0           $matched=1;
235             }
236            
237             #handles it if it is a int
238 0 0 0       if ( ($row[$int] =~ /^[0123456789]*$/ ) && (!$matched) ) {
239 0 0         if (!defined( $columns[$int] )) {
240 0           $rowinfo{type}='int';
241 0           $rowinfo{max}=$row[$int];
242 0           $rowinfo{min}=$row[$int];
243 0           $rowinfo{allownull}=$self->{allownull};
244 0           $columns[$int]=\%rowinfo;
245             }else {
246             #handles it if the type has not been set previously.
247 0 0         if (defined($columns[$int]{type})){
248 0           $columns[$int]{type}='int';
249             }
250              
251             #handles it if the last type was int as well
252 0 0         if ($columns[$int]{type} eq 'int') {
253             #updates the new min and max value, if needed
254 0 0         if ($columns[$int]{min} > $row[$int]) {
255 0           $columns[$int]{min}=$row[$int];
256             }
257 0 0         if ($columns[$int]{max} < $row[$int]) {
258 0           $columns[$int]{min}=$row[$int];
259             }
260             }
261             #handles it if it is a string
262 0 0         if ($columns[$int]{type} eq 'string') {
263             #updates the new min and max length, if needed
264 0           my $length=length($row[$int]);
265 0 0         if ($columns[$int]{min} > $length) {
266 0           $columns[$int]{min}=$length;
267             }
268 0 0         if ($columns[$int]{max} < $length) {
269 0           $columns[$int]{max}=$length;
270             }
271             }
272             #handles it if the last type was float
273 0 0         if ($columns[$int]{type} eq 'float') {
274             #updates the new min and max value, if needed
275 0 0         if ($columns[$int]{min} > $row[$int]) {
276 0           $columns[$int]{min}=$row[$int];
277             }
278 0 0         if ($columns[$int]{max} < $row[$int]) {
279 0           $columns[$int]{max}=$row[$int];
280             }
281             }
282             }
283 0           $matched=1;
284             }
285              
286             #handles it if it is a float
287 0 0 0       if ( ($row[$int] =~ /^[0123456789]*\.[0123456789]*$/ ) && (!$matched) ) {
288 0 0         if (!defined( $columns[$int] )) {
289 0           $rowinfo{type}='float';
290 0           $rowinfo{max}=$row[$int];
291 0           $rowinfo{min}=$row[$int];
292 0           $rowinfo{allownull}=$self->{allownull};
293 0           $columns[$int]=\%rowinfo;
294             }else {
295             #handles it if the type has not been set previously.
296 0 0         if (defined($columns[$int]{type})){
297 0           $columns[$int]{type}='float';
298             }
299              
300             #handles it if the last type was int as well
301 0 0         if ($columns[$int]{type} eq 'int') {
302             #updates the new min and max value, if needed
303 0 0         if ($columns[$int]{min} > $row[$int]) {
304 0           $columns[$int]{min}=$row[$int];
305             }
306 0 0         if ($columns[$int]{max} < $row[$int]) {
307 0           $columns[$int]{max}=$row[$int];
308             }
309             #change the type to float as int can also be a float value as well, but float is
310             #more accurate
311 0           $columns[$int]{type}='float';
312             }
313             #handles it if it is a string
314 0 0         if ($columns[$int]{type} eq 'string') {
315             #updates the new min and max length, if needed
316 0           my $length=length($row[$int]);
317 0 0         if ($columns[$int]{min} > $length) {
318 0           $columns[$int]{min}=$length;
319             }
320 0 0         if ($columns[$int]{max} < $length) {
321 0           $columns[$int]{max}=$length;
322             }
323             }
324             #handles it if the last type was float
325 0 0         if ($columns[$int]{type} eq 'float') {
326             #updates the new min and max value, if needed
327 0 0         if ($columns[$int]{min} > $row[$int]) {
328 0           $columns[$int]{min}=$row[$int];
329             }
330 0 0         if ($columns[$int]{max} < $row[$int]) {
331 0           $columns[$int]{max}=$row[$int];
332             }
333             }
334             }
335 0           $matched=1;
336             }
337              
338             #handles it if it was not matched, which in this case only leaves a string
339 0 0         if (!$matched) {
340 0 0         if (!defined( $columns[$int] )) {
341 0           $rowinfo{type}='string';
342 0           $rowinfo{allownull}=$self->{allownull};
343 0           my $length=length($row[$int]);
344 0           $columns[$int]{min}=$length;
345 0           $columns[$int]{max}=$length;
346 0           $columns[$int]=\%rowinfo;
347             }
348              
349             #just set this to a string instead of bothering to check if this was
350             #set to a int or float initially...
351 0           $columns[$int]{type}='string';
352              
353             #updates the new min and max length, if needed
354 0           my $length=length($row[$int]);
355 0 0 0       if ( (!defined( $columns[$int]{min} )) || ($columns[$int]{min} > $length) ) {
356 0           $columns[$int]{min}=$length;
357             }
358 0 0 0       if ( (!defined( $columns[$int]{max} )) || ($columns[$int]{max} < $length)) {
359 0           $columns[$int]{max}=$length;
360             }
361             }
362              
363 0           $int++;
364             }
365            
366             #fetches the new row and we do get it, save it as a array and if we don't stop this loop
367 0           $newrow=$self->{csv}->getline ($fh);
368 0 0         if (defined($newrow)) {
369 0           my @row = @{$newrow};
  0            
370             }else {
371 0           $continueloop=0;
372             }
373             }
374              
375             #runs through each one setting up the SQL information and handling any consistently nulls
376 0           my $int=0;
377 0           while (defined($columns[$int])) {
378 0 0         if (!defined($columns[$int]{type})) {
379 0           $columns[$int]{type}='string';
380 0           $columns[$int]{sql}='VARCHAR(1024)';
381 0           $columns[$int]{min}=0;
382 0           $columns[$int]{max}=1024;
383             }
384              
385 0 0         if ($columns[$int]{type} eq 'int') {
386 0           $columns[$int]{sql}='BIGINT';
387             }
388              
389 0 0         if ($columns[$int]{type} eq 'float') {
390 0           $columns[$int]{sql}='DOUBLE PRECISION';
391             }
392              
393 0 0         if ($columns[$int]{type} eq 'string') {
394 0           $columns[$int]{max}=((( $columns[$int]{max} / 1024) % 1024) + 1) * 1024;
395 0           $columns[$int]{sql}='VARCCHAR('.$columns[$int]{max}.')';
396             }
397              
398 0 0         if (!$columns[$int]{allownull}) {
399 0           $columns[$int]{sql}=$columns[$int]{sql}.' NOT NULL';
400             }
401              
402 0           $int++;
403             }
404              
405 0           return @columns;
406             }
407              
408             =head2 errorblank
409              
410             This blanks the error storage and is only meant for internal usage.
411              
412             If a permanent error is set, it will not be cleared.
413              
414             It does the following.
415              
416             $self->{error}=undef;
417             $self->{errorString}="";
418              
419             =cut
420              
421             sub errorblank{
422 0     0 1   my $self=$_[0];
423              
424 0 0         if ($self->{perror}) {
425 0           warn($self->{module}.' errorblank: A permanent error is set');
426 0           return undef;
427             }
428              
429 0           $self->{error}=undef;
430 0           $self->{errorString}="";
431              
432 0           return 1;
433             }
434              
435             =head1 ERROR CODES
436              
437             =head2 1
438              
439             No "Text::CSV" object specified or defined.
440              
441             =head2 2
442              
443             No file specified.
444              
445             =head3 3
446              
447             Failed to open the file.
448              
449             =head1 AUTHOR
450              
451             Zane C. Bowers, C<< >>
452              
453             =head1 BUGS
454              
455             Please report any bugs or feature requests to C, or through
456             the web interface at L. I will be notified, and then you'll
457             automatically be notified of progress on your bug as I make changes.
458              
459              
460              
461              
462             =head1 SUPPORT
463              
464             You can find documentation for this module with the perldoc command.
465              
466             perldoc Text::CSV::SQLhelper
467              
468              
469             You can also look for information at:
470              
471             =over 4
472              
473             =item * RT: CPAN's request tracker
474              
475             L
476              
477             =item * AnnoCPAN: Annotated CPAN documentation
478              
479             L
480              
481             =item * CPAN Ratings
482              
483             L
484              
485             =item * Search CPAN
486              
487             L
488              
489             =back
490              
491              
492             =head1 ACKNOWLEDGEMENTS
493              
494              
495             =head1 COPYRIGHT & LICENSE
496              
497             Copyright 2010 Zane C. Bowers, all rights reserved.
498              
499             This program is free software; you can redistribute it and/or modify it
500             under the same terms as Perl itself.
501              
502              
503             =cut
504              
505             1; # End of Text::CSV::SQLhelper