File Coverage

blib/lib/DBIx/Class/_Util.pm
Criterion Covered Total %
statement 98 132 74.2
branch 39 80 48.7
condition 12 42 28.5
subroutine 29 33 87.8
pod 0 13 0.0
total 178 300 59.3


line stmt bran cond sub pod time code
1             package # hide from PAUSE
2             DBIx::Class::_Util;
3              
4 385     385   49223858 use warnings;
  385         2770  
  385         11988  
5 385     385   2095 use strict;
  385         993  
  385         16601  
6              
7             use constant SPURIOUS_VERSION_CHECK_WARNINGS => (
8 385 50 33     34513 ( $ENV{DBICTEST_VERSION_WARNS_INDISCRIMINATELY} or $] < 5.010 )
9             ? 1
10             : 0
11 385     385   2198 );
  385         983  
12              
13             BEGIN {
14             package # hide from pause
15             DBIx::Class::_ENV_;
16              
17 385     385   2893 use Config;
  385         1087  
  385         65560  
18              
19             use constant {
20              
21             # but of course
22             BROKEN_FORK => ($^O eq 'MSWin32') ? 1 : 0,
23              
24             BROKEN_GOTO => ($] < '5.008003') ? 1 : 0,
25              
26             HAS_ITHREADS => $Config{useithreads} ? 1 : 0,
27              
28             UNSTABLE_DOLLARAT => ( "$]" < 5.013002 ) ? 1 : 0,
29              
30             DBICTEST => $INC{"DBICTest/Util.pm"} ? 1 : 0,
31              
32             # During 5.13 dev cycle HELEMs started to leak on copy
33             # add an escape for these perls ON SMOKERS - a user will still get death
34             PEEPEENESS => ( eval { DBICTest::RunMode->is_smoker } && ($] >= 5.013005 and $] <= 5.013006) ),
35              
36             SHUFFLE_UNORDERED_RESULTSETS => $ENV{DBIC_SHUFFLE_UNORDERED_RESULTSETS} ? 1 : 0,
37              
38             ASSERT_NO_INTERNAL_WANTARRAY => $ENV{DBIC_ASSERT_NO_INTERNAL_WANTARRAY} ? 1 : 0,
39              
40             ASSERT_NO_INTERNAL_INDIRECT_CALLS => $ENV{DBIC_ASSERT_NO_INTERNAL_INDIRECT_CALLS} ? 1 : 0,
41              
42             STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE => $ENV{DBIC_STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE} ? 1 : 0,
43              
44             IV_SIZE => $Config{ivsize},
45              
46 385 50 33     8920 OS_NAME => $^O,
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
47 385     385   2736 };
  385         1086  
48              
49 385 50   385   2538 if ($] < 5.009_005) {
50 0         0 require MRO::Compat;
51 0         0 constant->import( OLD_MRO => 1 );
52             }
53             else {
54 385         31946 require mro;
55 385         67992 constant->import( OLD_MRO => 0 );
56             }
57             }
58              
59             # FIXME - this is not supposed to be here
60             # Carp::Skip to the rescue soon
61 385     385   169027 use DBIx::Class::Carp '^DBIx::Class|^DBICTest';
  385         1059  
  385         2651  
62              
63 385     385   2592 use B ();
  385         989  
  385         7741  
64 385     385   2059 use Carp 'croak';
  385         933  
  385         20652  
65 385     385   245730 use Storable 'nfreeze';
  385         1220350  
  385         26500  
66 385     385   2965 use Scalar::Util qw(weaken blessed reftype refaddr);
  385         1120  
  385         26469  
67 385     385   2534 use List::Util qw(first);
  385         1039  
  385         25325  
68 385     385   197320 use Sub::Quote qw(qsub quote_sub);
  385         1843074  
  385         26803  
69              
70 385     385   3011 use base 'Exporter';
  385         993  
  385         59778  
71             our @EXPORT_OK = qw(
72             sigwarn_silencer modver_gt_or_eq modver_gt_or_eq_and_lt
73             fail_on_internal_wantarray fail_on_internal_call
74             refdesc refcount hrefaddr
75             scope_guard is_exception detected_reinvoked_destructor
76             quote_sub qsub perlstring serialize
77             UNRESOLVABLE_CONDITION
78             );
79              
80 385     385   2793 use constant UNRESOLVABLE_CONDITION => \ '1 = 0';
  385         1137  
  385         673406  
81              
82             sub sigwarn_silencer ($) {
83 92     92 0 7023194582 my $pattern = shift;
84              
85 92 50       2473 croak "Expecting a regexp" if ref $pattern ne 'Regexp';
86              
87 92   100 0   5795 my $orig_sig_warn = $SIG{__WARN__} || sub { CORE::warn(@_) };
  0         0  
88              
89 92 50   36   3831 return sub { &$orig_sig_warn unless $_[0] =~ $pattern };
  36         1790  
90             }
91              
92 31326     31326 0 311248 sub perlstring ($) { q{"}. quotemeta( shift ). q{"} };
93              
94 66954   50 66954 0 3394414 sub hrefaddr ($) { sprintf '0x%x', &refaddr||0 }
95              
96             sub refdesc ($) {
97 9769 50   9769 0 1296291 croak "Expecting a reference" if ! length ref $_[0];
98              
99             # be careful not to trigger stringification,
100             # reuse @_ as a scratch-pad
101 9769 100       86112 sprintf '%s%s(0x%x)',
102             ( defined( $_[1] = blessed $_[0]) ? "$_[1]=" : '' ),
103             reftype $_[0],
104             refaddr($_[0]),
105             ;
106             }
107              
108             sub refcount ($) {
109 40069 50   40069 0 91943 croak "Expecting a reference" if ! length ref $_[0];
110              
111             # No tempvars - must operate on $_[0], otherwise the pad
112             # will count as an extra ref
113 40069         175214 B::svref_2object($_[0])->REFCNT;
114             }
115              
116             sub serialize ($) {
117 9418     9418 0 54530 local $Storable::canonical = 1;
118 9418         23774 nfreeze($_[0]);
119             }
120              
121             sub scope_guard (&) {
122 8 50   8 0 873 croak 'Calling scope_guard() in void context makes no sense'
123             if ! defined wantarray;
124              
125             # no direct blessing of coderefs - DESTROY is buggy on those
126 8         26 bless [ $_[0] ], 'DBIx::Class::_Util::ScopeGuard';
127             }
128             {
129             package #
130             DBIx::Class::_Util::ScopeGuard;
131              
132             sub DESTROY {
133 8     8   123 &DBIx::Class::_Util::detected_reinvoked_destructor;
134              
135 8         11 local $@ if DBIx::Class::_ENV_::UNSTABLE_DOLLARAT;
136              
137             eval {
138 8         32 $_[0]->[0]->();
139 8         932 1;
140 8 50       10 } or do {
141 0         0 Carp::cluck "Execution of scope guard $_[0] resulted in the non-trappable exception:\n\n$@";
142             };
143             }
144             }
145              
146             sub is_exception ($) {
147 54841     54841 0 102207 my $e = $_[0];
148              
149             # this is not strictly correct - an eval setting $@ to undef
150             # is *not* the same as an eval setting $@ to ''
151             # but for the sake of simplicity assume the following for
152             # the time being
153 54841 50       116331 return 0 unless defined $e;
154              
155 54841         90090 my ($not_blank, $suberror);
156             {
157 54841         78144 local $@;
  54841         79795  
158 54841 100       94444 eval {
159 54841 100       121124 $not_blank = ($e ne '') ? 1 : 0;
160 54838         146887 1;
161             } or $suberror = $@;
162             }
163              
164 54841 100       121410 if (defined $suberror) {
165 3 50       29 if (length (my $class = blessed($e) )) {
166 3         42 carp_unique( sprintf(
167             'External exception class %s implements partial (broken) overloading '
168             . 'preventing its instances from being used in simple ($x eq $y) '
169             . 'comparisons. Given Perl\'s "globally cooperative" exception '
170             . 'handling this type of brokenness is extremely dangerous on '
171             . 'exception objects, as it may (and often does) result in silent '
172             . '"exception substitution". DBIx::Class tries to work around this '
173             . 'as much as possible, but other parts of your software stack may '
174             . 'not be even aware of this. Please submit a bugreport against the '
175             . 'distribution containing %s and in the meantime apply a fix similar '
176             . 'to the one shown at %s, in order to ensure your exception handling '
177             . 'is saner application-wide. What follows is the actual error text '
178             . "as generated by Perl itself:\n\n%s\n ",
179             $class,
180             $class,
181             'http://v.gd/DBIC_overload_tempfix/',
182             $suberror,
183             ));
184              
185             # workaround, keeps spice flowing
186 3 50       52 $not_blank = ("$e" ne '') ? 1 : 0;
187             }
188             else {
189             # not blessed yet failed the 'ne'... this makes 0 sense...
190             # just throw further
191 0         0 die $suberror
192             }
193             }
194              
195 54841         155640 return $not_blank;
196             }
197              
198             {
199             my $destruction_registry = {};
200              
201             sub CLONE {
202             $destruction_registry = { map
203 0 0   0   0 { defined $_ ? ( refaddr($_) => $_ ) : () }
  0         0  
204             values %$destruction_registry
205             };
206             }
207              
208             # This is almost invariably invoked from within DESTROY
209             # throwing exceptions won't work
210             sub detected_reinvoked_destructor {
211              
212             # quick "garbage collection" pass - prevents the registry
213             # from slowly growing with a bunch of undef-valued keys
214             defined $destruction_registry->{$_} or delete $destruction_registry->{$_}
215 59769   66 59769 0 2562657 for keys %$destruction_registry;
216              
217 59769 50       284466 if (! length ref $_[0]) {
    100          
218 0         0 printf STDERR '%s() expects a blessed reference %s',
219             (caller(0))[3],
220             Carp::longmess,
221             ;
222 0         0 return undef; # don't know wtf to do
223             }
224             elsif (! defined $destruction_registry->{ my $addr = refaddr($_[0]) } ) {
225 59768         245234 weaken( $destruction_registry->{$addr} = $_[0] );
226 59768         386487 return 0;
227             }
228             else {
229             carp_unique ( sprintf (
230             'Preventing *MULTIPLE* DESTROY() invocations on %s - an *EXTREMELY '
231             . 'DANGEROUS* condition which is *ALMOST CERTAINLY GLOBAL* within your '
232             . 'application, affecting *ALL* classes without active protection against '
233             . 'this. Diagnose and fix the root cause ASAP!!!%s',
234             refdesc $_[0],
235 1 50 33     5 ( ( $INC{'Devel/StackTrace.pm'} and ! do { local $@; eval { Devel::StackTrace->VERSION(2) } } )
236 0         0 ? " (likely culprit Devel::StackTrace\@@{[ Devel::StackTrace->VERSION ]} found in %INC, http://is.gd/D_ST_refcap)"
237             : ''
238             )
239             ));
240              
241 1         120 return 1;
242             }
243             }
244             }
245              
246             sub modver_gt_or_eq ($$) {
247 256     256 0 2725 my ($mod, $ver) = @_;
248              
249 256 50 33     2355 croak "Nonsensical module name supplied"
250             if ! defined $mod or ! length $mod;
251              
252 256 50 33     29516 croak "Nonsensical minimum version supplied"
253             if ! defined $ver or $ver =~ /[^0-9\.\_]/;
254              
255 256         1222 local $SIG{__WARN__} = sigwarn_silencer( qr/\Qisn't numeric in subroutine entry/ )
256             if SPURIOUS_VERSION_CHECK_WARNINGS;
257              
258 256 50       6094 croak "$mod does not seem to provide a version (perhaps it never loaded)"
259             unless $mod->VERSION;
260              
261 256         1126 local $@;
262 256 50       651 eval { $mod->VERSION($ver) } ? 1 : 0;
  256         3761  
263             }
264              
265             sub modver_gt_or_eq_and_lt ($$$) {
266 3     3 0 248 my ($mod, $v_ge, $v_lt) = @_;
267              
268 3 50 33     34 croak "Nonsensical maximum version supplied"
269             if ! defined $v_lt or $v_lt =~ /[^0-9\.\_]/;
270              
271             return (
272 3 50 33     12 modver_gt_or_eq($mod, $v_ge)
273             and
274             ! modver_gt_or_eq($mod, $v_lt)
275             ) ? 1 : 0;
276             }
277              
278             {
279             my $list_ctx_ok_stack_marker;
280              
281             sub fail_on_internal_wantarray () {
282 0 0   0 0   return if $list_ctx_ok_stack_marker;
283              
284 0 0         if (! defined wantarray) {
285 0           croak('fail_on_internal_wantarray() needs a tempvar to save the stack marker guard');
286             }
287              
288 0           my $cf = 1;
289 0   0       while ( ( (caller($cf+1))[3] || '' ) =~ / :: (?:
290              
291             # these are public API parts that alter behavior on wantarray
292             search | search_related | slice | search_literal
293              
294             |
295              
296             # these are explicitly prefixed, since we only recognize them as valid
297             # escapes when they come from the guts of CDBICompat
298             CDBICompat .*? :: (?: search_where | retrieve_from_sql | retrieve_all )
299              
300             ) $/x ) {
301 0           $cf++;
302             }
303              
304 0           my ($fr, $want, $argdesc);
305             {
306 0           package DB;
307 0           $fr = [ caller($cf) ];
308 0           $want = ( caller($cf-1) )[5];
309 0 0         $argdesc = ref $DB::args[0]
310             ? DBIx::Class::_Util::refdesc($DB::args[0])
311             : 'non '
312             ;
313             };
314              
315 0 0 0       if (
316             $want and $fr->[0] =~ /^(?:DBIx::Class|DBICx::)/
317             ) {
318             DBIx::Class::Exception->throw( sprintf (
319             "Improper use of %s instance in list context at %s line %d\n\n Stacktrace starts",
320 0           $argdesc, @{$fr}[1,2]
  0            
321             ), 'with_stacktrace');
322             }
323              
324 0           my $mark = [];
325 0           weaken ( $list_ctx_ok_stack_marker = $mark );
326 0           $mark;
327             }
328             }
329              
330             sub fail_on_internal_call {
331 0     0 0   my ($fr, $argdesc);
332             {
333 0           package DB;
334 0           $fr = [ caller(1) ];
335 0 0         $argdesc = ref $DB::args[0]
336             ? DBIx::Class::_Util::refdesc($DB::args[0])
337             : undef
338             ;
339             };
340              
341 0 0 0       if (
      0        
342             $argdesc
343             and
344             $fr->[0] =~ /^(?:DBIx::Class|DBICx::)/
345             and
346             $fr->[1] !~ /\b(?:CDBICompat|ResultSetProxy)\b/ # no point touching there
347             ) {
348             DBIx::Class::Exception->throw( sprintf (
349             "Illegal internal call of indirect proxy-method %s() with argument %s: examine the last lines of the proxy method deparse below to determine what to call directly instead at %s on line %d\n\n%s\n\n Stacktrace starts",
350 0   0       $fr->[3], $argdesc, @{$fr}[1,2], ( $fr->[6] || do {
  0            
351             require B::Deparse;
352 385     385   3394 no strict 'refs';
  385         1197  
  385         45458  
353             B::Deparse->new->coderef2text(\&{$fr->[3]})
354             }),
355             ), 'with_stacktrace');
356             }
357             }
358              
359             1;