File Coverage

blib/lib/DBIx/Log4perl/db.pm
Criterion Covered Total %
statement 25 263 9.5
branch 0 150 0.0
condition 0 85 0.0
subroutine 8 31 25.8
pod 15 16 93.7
total 48 545 8.8


line stmt bran cond sub pod time code
1             # $Id: db.pm 245 2006-07-25 14:20:59Z martin $
2 2     2   8 use strict;
  2         4  
  2         63  
3 2     2   9 use warnings;
  2         3  
  2         50  
4 2     2   4924 use DBI;
  2         40298  
  2         129  
5 2     2   21 use Log::Log4perl;
  2         5  
  2         18  
6 2     2   89 use Data::Dumper;
  2         4  
  2         140  
7              
8             package DBIx::Log4perl::db;
9             @DBIx::Log4perl::db::ISA = qw(DBI::db DBIx::Log4perl);
10 2     2   10 use DBIx::Log4perl::Constants qw (:masks $LogMask);
  2         3  
  2         486  
11              
12             # $_glogger is not relied upon - it is just a fallback
13             my $_glogger;
14              
15             my $_counter; # to hold sub to count
16              
17             BEGIN {
18             my $x = sub {
19 2         4 my $start = shift;
20 2     2   8 return sub {$start++}};
  2         3983  
  0         0  
21 2         5 $_counter = &$x(0); # used to count dbh connections
22             }
23              
24              
25             sub STORE{
26 0     0     my $dbh = shift;
27 0           my @args = @_;
28              
29 0           my $h = $dbh->{private_DBIx_Log4perl};
30             # as we don't set private_DBIx_Log4perl until the connect method sometimes
31             # $h will not be set
32 0 0 0       $dbh->_dbix_l4p_debug($h, 2, "STORE($h->{dbh_no})", @args)
33             if ($h && ($h->{logmask} & DBIX_L4P_LOG_INPUT));
34              
35              
36 0           return $dbh->SUPER::STORE(@args);
37             }
38              
39             sub get_info
40             {
41 0     0 1   my ($dbh, @args) = @_;
42              
43 0           my $h = $dbh->{private_DBIx_Log4perl};
44 0           my $value = $dbh->SUPER::get_info(@args);
45              
46 0 0         $dbh->_dbix_l4p_debug($h, 2, "get_info($h->{dbh_no})", @args, $value)
47             if ($h->{logmask} & DBIX_L4P_LOG_INPUT);
48 0           return $value;
49             }
50             sub prepare {
51 0     0 1   my($dbh, @args) = @_;
52              
53 0           my $h = $dbh->{private_DBIx_Log4perl};
54 0           my $ctr = $h->{new_stmt_no}(); # get a new unique stmt counter in this dbh
55 0 0 0       if (($h->{logmask} & (DBIX_L4P_LOG_INPUT|DBIX_L4P_LOG_SQL)) &&
      0        
56             (caller !~ /^DBIx::Log4perl/o) &&
57             (caller !~ /^DBD::/o)) { # e.g. from selectall_arrayref
58 0           $dbh->_dbix_l4p_debug($h, 2, "prepare($h->{dbh_no}.$ctr)", $args[0]);
59             }
60              
61 0           my $sth = $dbh->SUPER::prepare(@args);
62 0 0         if ($sth) {
63 0           $sth->{private_DBIx_Log4perl} = $h;
64 0           $sth->{private_DBIx_st_no} = $ctr;
65             }
66              
67 0           return $sth;
68             }
69              
70             sub prepare_cached {
71 0     0 1   my($dbh, @args) = @_;
72              
73 0           my $h = $dbh->{private_DBIx_Log4perl};
74 0           my $ctr = $h->{new_stmt_no}();
75 0 0 0       if (($h->{logmask} & (DBIX_L4P_LOG_INPUT|DBIX_L4P_LOG_SQL)) &&
      0        
76             (caller !~ /^DBIx::Log4perl/o) &&
77             (caller !~ /^DBD::/o)) { # e.g. from selectall_arrayref
78 0           $dbh->_dbix_l4p_debug($h, 2,
79             "prepare_cached($h->{dbh_no}.$ctr)", $args[0]);
80             }
81              
82 0           my $sth = $dbh->SUPER::prepare_cached(@args);
83 0 0         if ($sth) {
84 0           $sth->{private_DBIx_Log4perl} = $h;
85 0           $sth->{private_DBIx_st_no} = $ctr;
86             }
87 0           return $sth;
88             }
89              
90             sub do {
91 0     0 1   my ($dbh, @args) = @_;
92 0           my $h = $dbh->{private_DBIx_Log4perl};
93              
94 0           $h->{Statement} = $args[0];
95 0 0         $dbh->_dbix_l4p_debug($h, 2, "do($h->{dbh_no})", @args)
96             if ($h->{logmask} & (DBIX_L4P_LOG_INPUT|DBIX_L4P_LOG_SQL));
97              
98 0           my $affected = $dbh->SUPER::do(@args);
99              
100 0 0 0       if (!defined($affected)) {
    0 0        
    0 0        
101 0 0 0       $dbh->_dbix_l4p_error(2, 'do error for ', @args)
102             if (($h->{logmask} & DBIX_L4P_LOG_ERRCAPTURE) &&
103             !($h->{logmask} & DBIX_L4P_LOG_INPUT)); # not already logged
104             } elsif (defined($affected) && $affected eq '0E0' &&
105             ($h->{logmask} & DBIX_L4P_LOG_WARNINGS)) {
106 0           $dbh->_dbix_l4p_warning(2, 'no effect from ', @args);
107             } elsif (($affected ne '0E0') && ($h->{logmask} & DBIX_L4P_LOG_INPUT)) {
108 0           $dbh->_dbix_l4p_debug($h, 2, "affected($h->{dbh_no})", $affected);
109 0 0         $dbh->_dbix_l4p_debug($h, 2, "\t" . $dbh->SUPER::errstr)
110             if (!defined($affected));
111             }
112 0           return $affected;
113             }
114              
115             sub selectrow_array {
116 0     0 1   my ($dbh, @args) = @_;
117              
118 0           my $h = $dbh->{private_DBIx_Log4perl};
119              
120 0 0         if ($h->{logmask} & (DBIX_L4P_LOG_INPUT|DBIX_L4P_LOG_SQL)) {
121 0 0 0       if ((scalar(@args) > 0) && (ref $args[0])) {
122 0           $dbh->_dbix_l4p_debug($h,
123             2,
124             "selectrow_array($h->{dbh_no}." .
125             $args[0]->{private_DBIx_st_no} . ")", @args);
126             } else {
127 0           $dbh->_dbix_l4p_debug($h, 2,
128             "selectrow_array($h->{dbh_no})", @args);
129             }
130             }
131              
132 0 0         if (wantarray) {
133 0           my @ret = $dbh->SUPER::selectrow_array(@args);
134 0 0         $dbh->_dbix_l4p_debug($h, 2, "result($h->{dbh_no})", @ret)
135             if ($h->{logmask} & DBIX_L4P_LOG_OUTPUT);
136 0           return @ret;
137              
138             } else {
139 0           my $ret = $dbh->SUPER::selectrow_array(@args);
140 0 0         $dbh->_dbix_l4p_debug($h, 2, "result($h->{dbh_no})", $ret)
141             if ($h->{logmask} & DBIX_L4P_LOG_OUTPUT);
142 0           return $ret;
143             }
144             }
145              
146             sub selectrow_arrayref {
147 0     0 1   my ($dbh, @args) = @_;
148              
149 0           my $h = $dbh->{private_DBIx_Log4perl};
150              
151 0 0         if ($h->{logmask} & (DBIX_L4P_LOG_INPUT|DBIX_L4P_LOG_SQL)) {
152 0 0 0       if ((scalar(@args) > 0) && (ref $args[0])) {
153 0           $dbh->_dbix_l4p_debug(
154             $h, 2,
155             "selectrow_arrayref($h->{dbh_no}." .
156             $args[0]->{private_DBIx_st_no} . ")", @args);
157             } else {
158 0           $dbh->_dbix_l4p_debug(
159             $h, 2, "selectrow_arrayref($h->{dbh_no})", @args);
160             }
161             }
162              
163 0           my $ref = $dbh->SUPER::selectrow_arrayref(@args);
164 0 0         $dbh->_dbix_l4p_debug($h, 2, "result($h->{dbh_no})", $ref)
165             if ($h->{logmask} & DBIX_L4P_LOG_OUTPUT);
166 0           return $ref;
167             }
168              
169             sub selectrow_hashref {
170 0     0 1   my ($dbh, @args) = @_;
171              
172 0           my $h = $dbh->{private_DBIx_Log4perl};
173              
174 0 0         if ($h->{logmask} & (DBIX_L4P_LOG_INPUT|DBIX_L4P_LOG_SQL)) {
175 0 0 0       if ((scalar(@args) > 0) && (ref $args[0])){
176 0           $dbh->_dbix_l4p_debug(
177             $h, 2,
178             "selectrow_hashref($h->{dbh_no}." .
179             $args[0]->{private_DBIx_st_no} . ")", @args)
180             } else {
181 0           $dbh->_dbix_l4p_debug($h, 2,
182             "selectrow_hashref($h->{dbh_no})", @args);
183             }
184             }
185              
186 0           my $ref = $dbh->SUPER::selectrow_hashref(@args);
187             # no need to show result - fetch will do this
188 0           return $ref;
189              
190             }
191              
192             sub selectall_arrayref {
193 0     0 1   my ($dbh, @args) = @_;
194              
195 0           my $h = $dbh->{private_DBIx_Log4perl};
196 0 0         if ($h->{logmask} & (DBIX_L4P_LOG_INPUT|DBIX_L4P_LOG_SQL)) {
197 0 0 0       if ((scalar(@args) > 0) && (ref $args[0])) {
198 0           $dbh->_dbix_l4p_debug(
199             $h, 2,
200             "selectall_arrayref($h->{dbh_no}." .
201             $args[0]->{private_DBIx_st_no} . ")", @args);
202             } else {
203 0           $dbh->_dbix_l4p_debug(
204             $h, 2, "selectall_arrayref($h->{dbh_no})", @args);
205             }
206             }
207              
208 0           my $ref = $dbh->SUPER::selectall_arrayref(@args);
209 0 0         $dbh->_dbix_l4p_debug($h, 2, "result($h->{dbh_no})", $ref)
210             if ($h->{logmask} & DBIX_L4P_LOG_OUTPUT);
211 0           return $ref;
212             }
213              
214             sub selectall_hashref {
215 0     0 1   my ($dbh, @args) = @_;
216              
217 0           my $h = $dbh->{private_DBIx_Log4perl};
218 0 0         if ($h->{logmask} & (DBIX_L4P_LOG_INPUT|DBIX_L4P_LOG_SQL)) {
219 0 0 0       if ((scalar(@args) > 0) && (ref $args[0])) {
220 0           $dbh->_dbix_l4p_debug(
221             $h, 2,
222             "selectall_hashref($h->{dbh_no}." .
223             $args[0]->{private_DBIx_st_no} . ")", @args);
224             } else {
225 0           $dbh->_dbix_l4p_debug($h, 2,
226             "selectall_hashref($h->{dbh_no})", @args);
227             }
228             }
229              
230 0           my $ref = $dbh->SUPER::selectall_hashref(@args);
231             # no need to show result - fetch will do this
232 0           return $ref;
233              
234             }
235              
236             sub _make_counter {
237 0     0     my $start = shift;
238 0     0     return sub {$start++}
239 0           };
240              
241             sub connected {
242              
243 0     0 0   my ($dbh, $dsn, $user, $pass, $attr) = @_;
244              
245 0           my %h = ();
246 0           $h{dbh_no} = &$_counter();
247 0           $h{new_stmt_no} = _make_counter(0); # get a new stmt count for this dbh
248              
249 0 0         if ($attr) {
250             # check we have not got dbix_l4p_init without dbix_l4p_log or vice versa
251 0           my ($a, $b) = (exists($attr->{dbix_l4p_init}),
252             exists($attr->{dbix_l4p_class}));
253 0 0 0       croak ('dbix_l4p_init specified without dbix_l4p_class or vice versa')
254             if (($a xor $b));
255             # if passed a Log4perl log handle use that
256 0 0 0       if (exists($attr->{dbix_l4p_logger})) {
    0          
257 0           $h{logger} = $attr->{dbix_l4p_logger};
258             } elsif ($a && $b) {
259 0           Log::Log4perl->init($attr->{dbix_l4p_init});
260 0           $h{logger} = Log::Log4perl->get_logger($attr->{dbix_l4p_class});
261 0           $h{init} = $attr->{dbix_l4p_init};
262 0           $h{class} = $attr->{dbix_l4p_class};
263             } else {
264 0           $h{logger} = Log::Log4perl->get_logger('DBIx::Log4perl');
265             }
266             # save log mask
267 0 0         $h{logmask} = $attr->{dbix_l4p_logmask}
268             if (exists($attr->{dbix_l4p_logmask}));
269             # save error regexp
270 0 0         $h{err_regexp} = $attr->{dbix_l4p_ignore_err_regexp}
271             if (exists($attr->{dbix_l4p_ignore_err_regexp}));
272             # remove our attrs from connection attrs
273             #delete $attr->{dbix_l4p_init};
274             #delete $attr->{dbix_l4p_class};
275             #delete $attr->{dbix_l4p_logger};
276             #delete $attr->{dbix_l4p_logmask};
277             #delete $attr->{dbix_l4p_ignore_err_regexp};
278             }
279             # take global log mask if non defined
280 0 0         $h{logmask} = $LogMask unless (exists($h{logmask}));
281              
282 0 0         $h{logger} = Log::Log4perl->get_logger('DBIx::Log4perl')
283             unless (exists($h{logger}));
284 0           $_glogger = $h{logger};
285              
286             # make sure you don't change the depth before calling get_logger:
287 0           local $Log::Log4perl::caller_depth = $Log::Log4perl::caller_depth + 4;
288              
289 0           $h{dbd_specific} = 0;
290 0           $h{driver} = $dbh->{Driver}->{Name};
291              
292 0           $dbh->{private_DBIx_Log4perl} = \%h;
293              
294 0 0         if ($h{logmask} & DBIX_L4P_LOG_CONNECT) {
295 0           local $Data::Dumper::Indent = 0;
296 0 0         $h{logger}->debug(
    0          
297             "connect($h{dbh_no}): " .
298             (defined($dsn) ? $dsn : '') . ', ' .
299             (defined($user) ? $user : '') . ', ' .
300             Data::Dumper->Dump([$attr], [qw(attr)]));
301 2     2   13 no strict 'refs';
  2         4  
  2         3358  
302 0           my $v = "DBD::" . $dbh->{Driver}->{Name} . "::VERSION";
303 0           $h{logger}->info("DBI: " . $DBI::VERSION,
304             ", DBIx::Log4perl: " . $DBIx::Log4perl::VERSION .
305             ", Driver: " . $h{driver} . "(" .
306             $$v . ")");
307             }
308              
309             #
310             # If capturing errors then save any error handler and set_err Handler
311             # passed to us and replace with our own.
312             #
313 0 0         if ($h{logmask} & DBIX_L4P_LOG_ERRCAPTURE) {
314 0 0         $h{HandleError} = $attr->{HandleError}
315             if (exists($attr->{HandleError}));
316 0 0         $h{HandleSetErr} = $attr->{HandleSetErr}
317             if (exists($attr->{HandleSetErr}));
318 0           $dbh->{HandleError} = \&_error_handler;
319 0           $dbh->{HandleSetErr} = \&_set_err_handler;
320             }
321 0           return;
322              
323             }
324             sub clone {
325 0     0 1   my ($dbh, @args) = @_;
326              
327 0           my $h = $dbh->{private_DBIx_Log4perl};
328 0 0         if ($h->{logmask} & DBIX_L4P_LOG_CONNECT) {
329 0           $dbh->_dbix_l4p_debug($h, 2, "clone($h->{dbh_no})", @args);
330             }
331              
332 0           return $dbh->SUPER::clone(@args);
333             }
334              
335             sub disconnect {
336 0     0 1   my $dbh = shift;
337              
338 0 0         if ($dbh) {
339 0           my $h;
340 0           eval {
341             # Avoid
342             # (in cleanup) Can't call method "FETCH" on an undefined value
343 0           $h = $dbh->{private_DBIx_Log4perl};
344             };
345 0 0 0       if (!$@ && $h && defined($h->{logger})) {
      0        
346 0 0         if ($h->{logmask} & DBIX_L4P_LOG_CONNECT) {
347 0           local $Log::Log4perl::caller_depth =
348             $Log::Log4perl::caller_depth + 2;
349 0           $dbh->_dbix_l4p_debug($h, 2, "disconnect($h->{dbh_no})");
350             }
351             }
352             }
353 0           return $dbh->SUPER::disconnect;
354              
355             }
356              
357             sub begin_work {
358 0     0 1   my $dbh = shift;
359 0           my $h = $dbh->{private_DBIx_Log4perl};
360              
361 0 0         $dbh->_dbix_l4p_debug($h, 2, "start transaction($h->{dbh_no})")
362             if ($h->{logmask} & DBIX_L4P_LOG_TXN);
363              
364 0           return $dbh->SUPER::begin_work;
365             }
366              
367             sub rollback {
368 0     0 1   my $dbh = shift;
369 0           my $h = $dbh->{private_DBIx_Log4perl};
370              
371 0 0         $dbh->_dbix_l4p_debug($h, 2, "roll back($h->{dbh_no})")
372             if ($h->{logmask} & DBIX_L4P_LOG_TXN);
373              
374 0           return $dbh->SUPER::rollback;
375             }
376              
377             sub commit {
378 0     0 1   my $dbh = shift;
379              
380 0           my $h = $dbh->{private_DBIx_Log4perl};
381 0 0         $dbh->_dbix_l4p_debug($h, 2, "commit($h->{dbh_no})")
382             if ($h->{logmask} & DBIX_L4P_LOG_TXN);
383              
384 0           return $dbh->SUPER::commit;
385             }
386              
387             sub last_insert_id {
388 0     0 1   my ($dbh, @args) = @_;
389 0           my $h = $dbh->{private_DBIx_Log4perl};
390              
391 0     0     $dbh->_dbix_l4p_debug($h, 2,
392             sub {Data::Dumper->Dump([\@args], ["last_insert_id($h->{dbh_no})"])})
393 0 0         if ($h->{logmask} & DBIX_L4P_LOG_INPUT);
394              
395 0           my $ret = $dbh->SUPER::last_insert_id(@args);
396 0     0     $dbh->_dbix_l4p_debug($h, 2, sub {"\t" . DBI::neat($ret)})
397 0 0         if ($h->{logmask} & DBIX_L4P_LOG_INPUT);
398 0           return $ret;
399             }
400              
401              
402             #
403             # Error handler to capture errors and log them
404             # Whatever, errors are passed on.
405             # if the user of DBIx::Log4perl passed in an error handler that is called
406             # before returning.
407             #
408             sub _error_handler {
409 0     0     my ($msg, $handle, $method_ret) = @_;
410              
411 0           local $Log::Log4perl::caller_depth = $Log::Log4perl::caller_depth + 1;
412              
413 0           my $dbh = $handle;
414 0           my $lh;
415 0           my $h = $handle->{private_DBIx_Log4perl};
416 0           my $out = '';
417              
418 0           $lh = $_glogger;
419 0 0 0       $lh = $h->{logger} if ($h && exists($h->{logger}));
420 0 0         return 0 if (!$lh);
421              
422 0 0 0       if ($h && exists($h->{err_regexp})) {
423 0 0         if ($dbh->err =~ $h->{err_regexp}) {
424 0           goto FINISH;
425             }
426             }
427             # start with error message, state and err
428 0           $out .= ' ' . '=' x 60 . "\n $msg\n";
429 0           $out .= "err() = " . $handle->err . "\n";
430 0           $out .= "state() = " . $handle->state . "\n";
431              
432 0 0         if ($DBI::lasth) {
433 0 0         $out .= " lasth type: $DBI::lasth->{Type}\n"
434             if ($DBI::lasth->{Type});
435 0 0         $out .= " lasth Statement ($DBI::lasth):\n " .
436             "$DBI::lasth->{Statement}\n"
437             if ($DBI::lasth->{Statement});
438             }
439             # get db handle if we have an st
440 0           my $type = $handle->{Type};
441 0           my $sql;
442 0 0         if ($type eq 'st') { # given statement handle
443 0           $dbh = $handle->{Database};
444 0           $sql = $handle->{Statement};
445             } else {
446             # given db handle
447             # We've got other stmts under this db but we'll deal with those later
448 0           $sql = 'Possible SQL: ';
449 0 0         $sql .= "/$h->{Statement}/" if (exists($h->{Statement}));
450 0 0 0       $sql .= "/$dbh->{Statement}/"
      0        
451             if ($dbh->{Statement} &&
452             (exists($h->{Statement}) &&
453             ($dbh->{Statement} ne $h->{Statement})));
454             }
455              
456 0 0         my $dbname = exists($dbh->{Name}) ? $dbh->{Name} : "";
457 0 0         my $username = exists($dbh->{Username}) ? $dbh->{Username} : "";
458 0           $out .= " DB: $dbname, Username: $username\n";
459 0           $out .= " handle type: $type\n SQL: " . DBI::neat($sql) . "\n";
460 0           $out .= ' db Kids=' . $dbh->{Kids} .
461             ', ActiveKids=' . $dbh->{ActiveKids} . "\n";
462 0 0 0       $out .= " DB errstr: " . $handle->errstr . "\n"
463             if ($handle->errstr && ($handle->errstr ne $msg));
464              
465 0 0 0       if (exists($h->{ParamValues}) && $h->{ParamValues}) {
466 0           $out .= " ParamValues captured in HandleSetErr:\n ";
467 0           foreach (sort keys %{$h->{ParamValues}}) {
  0            
468 0           $out .= "$_=" . DBI::neat($h->{ParamValues}->{$_}) . ",";
469             }
470 0           $out .= "\n";
471             }
472 0 0         if ($type eq 'st') {
473 0           my $str = "";
474 0 0         if ($handle->{ParamValues}) {
475 0           foreach (sort keys %{$handle->{ParamValues}}) {
  0            
476 0           $str .= "$_=" . DBI::neat($handle->{ParamValues}->{$_}) . ",";
477             }
478             }
479 0           $out .= " ParamValues: $str\n";
480 0 0         $out .= " " .
481             Data::Dumper->Dump([$handle->{ParamArrays}], ['ParamArrays'])
482             if ($handle->{ParamArrays});
483             }
484 0           my @substmts;
485             # get list of statements under the db
486 0           push @substmts, $_ for (grep { defined } @{$dbh->{ChildHandles}});
  0            
  0            
487 0           $out .= " " . scalar(@substmts) . " sub statements:\n";
488 0 0         if (scalar(@substmts)) {
489 0           foreach my $stmt (@substmts) {
490 0           $out .= " stmt($stmt):\n";
491 0 0 0       $out .= ' SQL(' . $stmt->{Statement} . ")\n "
      0        
492             if ($stmt->{Statement} &&
493             (exists($h->{Statement}) &&
494             ($h->{Statement} ne $stmt->{Statement})));
495 0 0 0       if (exists($stmt->{ParamValues}) && $stmt->{ParamValues}) {
496 0           $out .= ' Params(';
497 0           foreach (sort keys %{$stmt->{ParamValues}}) {
  0            
498 0           $out .= "$_=" . DBI::neat($stmt->{ParamValues}->{$_}) . ",";
499             }
500 0           $out .= ")\n";
501             }
502             }
503             }
504              
505 0 0         if (exists($dbh->{Callbacks})) {
506 0           $out .= " Callbacks exist for " .
507 0           join(",", keys(%{$dbh->{Callbacks}})) . "\n";
508             }
509 0           local $Carp::MaxArgLen = 256;
510 0           $out .= " " .Carp::longmess("DBI error trap");
511 0           $out .= " " . "=" x 60 . "\n";
512 0           $lh->fatal($out);
513              
514             FINISH:
515 0 0 0       if ($h && exists($h->{ErrorHandler})) {
516 0           return $h->{ErrorHandler}($msg, $handle, $method_ret);
517             } else {
518 0           return 0; # pass error on
519             }
520             }
521              
522             #
523             # set_err handler so we can capture ParamValues before a statement
524             # is destroyed.
525             # If the use of DBIx::Log4perl passed in an error handler that is
526             # called before returning.
527             #
528             sub _set_err_handler {
529 0     0     my ($handle, $err, $errstr, $state, $method) = @_;
530              
531             # Capture ParamValues
532 0 0         if ($handle) {
533 0           my $h = $handle->{private_DBIx_Log4perl};
534 0 0         $h->{ParamValues} = $handle->{ParamValues}
535             if (exists($handle->{ParamValues}));
536 0 0         return $h->{HandleSetErr}(@_) if (exists($h->{HandleSetErr}));
537             }
538 0           return 0;
539             }
540              
541              
542             1;