File Coverage

blib/lib/DBD/TSM/Functions.pm
Criterion Covered Total %
statement 39 175 22.2
branch 0 62 0.0
condition 0 27 0.0
subroutine 13 18 72.2
pod 0 4 0.0
total 52 286 18.1


line stmt bran cond sub pod time code
1             #!/usr/local/bin/perl
2             # @(#)Functions.pm 1.12
3              
4             package DBD::TSM::Functions;
5              
6 1     1   4 use strict;
  1         2  
  1         23  
7 1     1   4 use warnings;
  1         1  
  1         27  
8 1     1   4 use Exporter;
  1         2  
  1         32  
9 1     1   861 use POSIX;
  1         7233  
  1         10  
10 1     1   2768 use Carp;
  1         2  
  1         53  
11              
12 1     1   5 use File::Spec;
  1         1  
  1         19  
13              
14 1     1   5 use constant DEBUG => 0;;
  1         2  
  1         60  
15 1     1   10 use constant DEBUG_LEVEL2 => 0;
  1         1  
  1         54  
16              
17             our $VERSION = 0.12;
18              
19             ##
20             ## Automatically replace during installation
21             ##
22              
23 1     1   4 use constant TSM_DSMADMC => quotemeta('/dsmadmc');
  1         1  
  1         33  
24 1     1   4 use constant TSM_DSMDIR => quotemeta('need_DSM_DIR');
  1         1  
  1         38  
25 1     1   4 use constant TSM_DSMCONFIG => quotemeta('need_DSM_SYS');
  1         1  
  1         29  
26 1     1   4 use Data::Dumper;
  1         14  
  1         1337  
27              
28             our @ISA = qw(Exporter);
29             our @EXPORT = qw(tsm_connect tsm_data_sources tsm_execute);
30              
31             # I do my best effort
32             sub tsm_choose_dsm_dir {
33 0 0 0 0 0   if (exists $ENV{DSM_DIR} and
      0        
      0        
34             -d $ENV{DSM_DIR} and
35             exists $ENV{DSM_CONFIG} and
36             -f $ENV{DSM_CONFIG}
37             ) {
38 0 0         my $dsm_config=(-f File::Spec->catfile($ENV{DSM_DIR},"dsm.sys"))?File::Spec->catfile($ENV{DSM_DIR},"dsm.sys"):
39             File::Spec->catfile($ENV{DSM_CONFIG});
40 0           DEBUG && carp "VAR: ", join(", ",$ENV{DSM_DIR}, File::Spec->catfile($ENV{DSM_DIR}, "dsmadmc"), $dsm_config), "\n";
41              
42 0           return ($ENV{DSM_DIR},
43             File::Spec->catfile($ENV{DSM_DIR},"dsmadmc"),
44             $dsm_config,
45             );
46             }
47 0 0 0       if (-f TSM_DSMADMC and
      0        
48             -d TSM_DSMDIR and
49             -f TSM_DSMCONFIG
50             ) {
51 0           return (TSM_DSMDIR,TSM_DSMADMC,TSM_DSMCONFIG);
52             }
53              
54 0           croak(__PACKAGE__,"->tsm_choose_dsm_dir: Cannot found DSM_DIR, DSMADMC, DSM_CONFIG\n");
55 0           return; #Never here
56             }
57              
58             sub _tsm_windows_cmd {
59 0     0     my @cmd = @_;
60 0           my $cmd;
61              
62 0           foreach my $elt (@cmd) {
63 0 0         if ($elt =~ m/\s+/) {
64 0           $elt = "\"$elt\"";
65             }
66 0           $cmd .= " $elt";
67             }
68              
69 0           DEBUG && carp "DEBUG - _tsm_windows_cmd: $cmd\n";
70              
71 0           return $cmd;
72             }
73              
74             sub tsm_connect {
75 0     0 0   my ($dbh, $dbname, $user, $auth)=@_;
76              
77 0           DEBUG && print "DEBUG - ",__PACKAGE__,"->tsm_connect: ",Dumper(\@_);
78              
79 0           $dbname = uc($dbname);
80              
81 0           my ($dsm_dir, $dsmadmc) = tsm_choose_dsm_dir();
82 0   0       $ENV{DSM_DIR} = $ENV{DSM_DIR} || $dsm_dir;
83              
84 0 0         unless (tsm_data_sources($dbh, $dbname)) {
85 0           $dbh->set_err(1,"Connect: Invalid dbname '$dbname'.");
86 0           return;
87             }
88              
89 0           @{$dbh->{tsm_connect}} = (
  0            
90             $dsmadmc,
91             "-servername=$dbname",
92             "-id=$user",
93             "-password=$auth",
94             );
95              
96 0           my @cmd = (
97 0           @{$dbh->{tsm_connect}},
98             "-quiet",
99             "query status",
100             );
101              
102 0           DEBUG && carp "DEBUG:", __PACKAGE__, "->tsm_connect: ", Dumper(\@cmd);
103              
104 0           my $rc_dsmadmc = 0;
105 0 0         if ($dbh->{tsm_pipe}) {
106 0           my $dsmadmc_h;
107 0 0         unless (open $dsmadmc_h, '-|', @cmd) {
108 0           $dbh->set_err(1,"Connect: Invalid user id or password '$user/$auth': $rc_dsmadmc/$!.");
109 0           return;
110             }
111 0           DEBUG && carp <$dsmadmc_h>;
112 0           close $dsmadmc_h;
113 0           $rc_dsmadmc = WEXITSTATUS($?);
114 0           DEBUG && carp "DEBUG:", __PACKAGE__, "->tsm_connect: rc=$?, text=$!, rcbis=$rc_dsmadmc";
115             } else {
116 0           my $cmd = _tsm_windows_cmd(@cmd);
117 0           my @query_status = qx($cmd);
118 0           $rc_dsmadmc = $?;
119             }
120            
121 0           DEBUG && carp "DEBUG:", __PACKAGE__, "->tsm_connect: rc=", $rc_dsmadmc;
122              
123 0 0         if ($rc_dsmadmc) {
124 0           $dbh->set_err(1,"Connect: Invalid user id or password '$user/$auth': $rc_dsmadmc/$!.");
125 0           return;
126             }
127              
128 0           return 1;
129             }
130              
131             sub tsm_data_sources {
132 0     0 0   my ($dbh,$data_source)=@_;
133              
134 0           my ($junk1, $junk2, $dsm_sys) = tsm_choose_dsm_dir();
135              
136 0           DEBUG && print "DEBUG - ",__PACKAGE__,"->tsm_data_sources: dsm.sys = $dsm_sys\n";
137              
138 0 0         unless (-r $dsm_sys) {
139 0           $dbh->DBI::set_err(1,"data sources: could not read file '$dsm_sys'.");
140 0           return;
141             }
142              
143 0           my $fh;
144 0 0         unless (open $fh, '<', $dsm_sys) {
145 0           $dbh->DBI::set_err(1,"data sources: could not open file '$dsm_sys'.");
146 0           return;
147             }
148              
149 0           my %data_sources;
150 0           local $_;
151 0           while (<$fh>) {
152 0           chomp;
153 0           DEBUG_LEVEL2 && warn "DEBUG - ", __PACKAGE__,"->tsm_data_sources: ", $_;
154 0 0         if (my ($server_name) = (m/^\s*[sS][eE]\w*\s+(\S+)/) ) {
155 0           $data_sources{uc($server_name)}++;
156             }
157             }
158 0           close $fh;
159              
160 0           DEBUG && print "DEBUG - ",__PACKAGE__,"->tsm_data_sources: ",Dumper(\%data_sources);
161              
162 0 0         if ($data_source) {
163 0 0         if (exists $data_sources{$data_source}) {
164 0           return 1;
165             } else {
166 0           $dbh->DBI::set_err(1,"data sources: could not find data source '$data_source'.");
167 0           return;
168             }
169             }
170              
171 0           my @data_sources=keys(%data_sources);
172 0           map {s/^/DBI:TSM:/} @data_sources;
  0            
173              
174 0           return (@data_sources);
175             }
176              
177             sub tsm_execute {
178 0     0 0   my ($sth, $statement)=@_;
179              
180 0           DEBUG && print "DEBUG - ",__PACKAGE__,"->tsm_execute: AutoCommit = ",$sth->FETCH('AutoCommit'),"\n";
181 0           my @cmd=@{$sth->{Database}->{tsm_connect}};
  0            
182 0 0         push(@cmd,'-itemcommit') if ($sth->FETCH('AutoCommit'));
183 0           push(@cmd,'-noconfirm','-displaymode=list',$statement);
184              
185 0           DEBUG && print "DEBUG - ",__PACKAGE__,"->tsm_execute: command = \"",join('" "',@cmd),"\"\n";
186              
187             # A changer dès que possible pour supporter les grosses tables
188             # Bidouille pour windows, à vérifier avec les dernières
189             # versions de Perl Windows
190 0           my ($rc_dsmadmc, @raw, $dsmadmc_h, $select_flag);
191 0 0         if ($sth->{tsm_pipe}) {
192 0 0         unless (open $dsmadmc_h, '-|', @cmd) {
193 0           $sth->DBI::set_err(1,"Cannot open '@cmd'.\n");
194 0           return;
195             }
196             } else {
197 0           my $cmd = _tsm_windows_cmd(@cmd);
198 0 0         unless (open($dsmadmc_h, "$cmd |")) {
199 0           $sth->DBI::set_err(1,"Cannot open '@cmd'.\n");
200 0           return;
201             }
202             }
203              
204             # On ne prend pas que les lignes intéressantes pour un select
205 0 0 0       $select_flag++ if ($statement =~ m/select/i or $statement =~ m/^\s*[qQ][uUeErRyY]*\s+/);
206 0           DEBUG && undef $select_flag;
207              
208 0           my $rc=0;
209 0           my $errstr="";
210              
211 0           my (@data, @fields, %fields, $not_first_raw, @values, $begin_data);
212 1     1   7 no warnings;
  1         1  
  1         606  
213              
214 0           DEBUG && warn "DEBUG: select_flag = $select_flag\n";
215              
216 0           local $_;
217 0           LINE: while (<$dsmadmc_h>) {
218 0 0         $errstr .= $_ if m/^[A-Z][A-Z][A-Z]\d\d\d\d[^I]/;
219              
220             # On prend tout si ce n'est pas un select
221 0 0         if (!$select_flag) {
222 0           push @raw, $_;
223             }
224              
225 0 0         if (m/^ANS8002I\s+Highest\s+return\s+code\s+was\s+(-?\d+)./) {
226 0           $rc = $1;
227 0           last LINE;
228             }
229              
230             # Pas besoin de traitement si ce n'est pas un select
231 0 0         next LINE if (!$select_flag);
232              
233             # Tant que l'on a pas le début, on saute cette partie
234             # Le jour ou on utilise dataonly => client ITSM > à 5.3
235             # partout
236 0 0         if (m/ANS8000I/) {
237 0           $begin_data++;
238 0           next LINE;
239             }
240 0 0         next LINE unless ($begin_data);
241             # On saute les messages
242 0 0         next LINE if (m/^\s*AN[SR]/);
243              
244 0           DEBUG && "DEBUG:Inside: $not_first_raw: $_\n";
245              
246 0 0         if ( my ($field, $value) = (m/\s*([^:]+):\s+(.*)/) ) {
247 0           push @values, $value;
248              
249             # Bidouille liée au fait que l'on utilise le style
250             # paragraphe (le seul pour avoir le nom des champs)
251 0 0         next LINE if $not_first_raw;
252              
253             # On stocke les champs lors de la première ligne
254 0 0         if (exists $fields{$field}) {
255             # On vérifie le cas des champs dupliqués dans le cas
256             # des jointures de table. On met un message
257             # Marchait pas avant marche comme ca maintenant, à mettre
258             # dans les bugs
259 0           warn "Functions.pm: Duplicate field '$field' !!! Move to 'Dup_$field'.\n";
260 0           $field = 'Dup_' . $field;
261              
262             }
263 0           $fields{$field}++;
264 0           push @fields, $field;
265 0           next LINE;
266             }
267              
268             # Fin d'un paragraphe
269 0 0 0       if (m/^\s*$/ and @fields and @values) {
      0        
270 0           DEBUG && warn "DEBUG:PARSE:", Dumper(\@fields, \@values);
271 0 0         if (@values != @fields) {
272             # On est dans l'auto debug pour avoir des remontées
273             # d'erreur
274 0           warn "Functions.pm: Bad number of values: ",
275             scalar(@values)," for", scalar(@fields),
276             " fields, request line number ", $not_first_raw+1, "\n";
277 0           DEBUG && warn "DEBUG: ", Dumper(\@fields, \@values);
278 0           next LINE;
279             }
280 0           $not_first_raw++; # C'est vrai à partir de maintenant
281              
282             # Pour pouvoir créer une référence anonyme, obligé
283             # de faire une recopie full mémoire : bof mais pas d'autres
284             # idées
285 0           my @for_ref = @values;
286              
287 0           push @data, \@for_ref;
288             # On réinitialise car on essaye de bosser en push
289 0           @values = ();
290             }
291             }
292 0           close $dsmadmc_h;
293 0           $rc_dsmadmc = $?;
294              
295             # On continue à donner de l'info même en cas d'erreur
296             # la partie rawdata peut aider à diagnostiquer la panne
297             # Ca sautera un jour car bouffe de la place
298 0 0         $sth->DBI::set_err($rc, $errstr) if ($rc);
299              
300 0           DEBUG && warn "DEBUG:Execute_data: ", Dumper(\@data, \@fields, \@raw);
301 0           return (\@data, \@fields, \@raw);
302             }
303              
304             1;