File Coverage

blib/lib/DBIx/Class/_Util.pm
Criterion Covered Total %
statement 98 132 74.2
branch 40 80 50.0
condition 13 42 30.9
subroutine 29 33 87.8
pod 0 13 0.0
total 180 300 60.0


line stmt bran cond sub pod time code
1             package # hide from PAUSE
2             DBIx::Class::_Util;
3              
4 385     385   8429604 use warnings;
  385         921  
  385         12067  
5 385     385   1700 use strict;
  385         766  
  385         17010  
6              
7             use constant SPURIOUS_VERSION_CHECK_WARNINGS => (
8 385 50 33     32391 ( $ENV{DBICTEST_VERSION_WARNS_INDISCRIMINATELY} or $] < 5.010 )
9             ? 1
10             : 0
11 385     385   1697 );
  385         678  
12              
13             BEGIN {
14             package # hide from pause
15             DBIx::Class::_ENV_;
16              
17 385     385   1805 use Config;
  385         740  
  385         64632  
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     8538 OS_NAME => $^O,
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
47 385     385   2038 };
  385         808  
48              
49 385 50   385   1607 if ($] < 5.009_005) {
50 0         0 require MRO::Compat;
51 0         0 constant->import( OLD_MRO => 1 );
52             }
53             else {
54 385         205185 require mro;
55 385         327854 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   163996 use DBIx::Class::Carp '^DBIx::Class|^DBICTest';
  385         831  
  385         2103  
62              
63 385     385   1982 use B ();
  385         652  
  385         7609  
64 385     385   1447 use Carp 'croak';
  385         519  
  385         20861  
65 385     385   260169 use Storable 'nfreeze';
  385         1202865  
  385         27812  
66 385     385   2562 use Scalar::Util qw(weaken blessed reftype refaddr);
  385         809  
  385         26906  
67 385     385   1950 use List::Util qw(first);
  385         694  
  385         34467  
68 385     385   221251 use Sub::Quote qw(qsub quote_sub);
  385         1728401  
  385         25217  
69              
70 385     385   2308 use base 'Exporter';
  385         759  
  385         47412  
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   1938 use constant UNRESOLVABLE_CONDITION => \ '1 = 0';
  385         1127  
  385         639436  
81              
82             sub sigwarn_silencer ($) {
83 91     91 0 6701992759 my $pattern = shift;
84              
85 91 50       3543 croak "Expecting a regexp" if ref $pattern ne 'Regexp';
86              
87 91   100 0   4075 my $orig_sig_warn = $SIG{__WARN__} || sub { CORE::warn(@_) };
  0         0  
88              
89 91 50   25   2911 return sub { &$orig_sig_warn unless $_[0] =~ $pattern };
  25         1335  
90             }
91              
92 31254     31254 0 268946 sub perlstring ($) { q{"}. quotemeta( shift ). q{"} };
93              
94 46107   50 46107 0 1165790 sub hrefaddr ($) { sprintf '0x%x', &refaddr||0 }
95              
96             sub refdesc ($) {
97 6848 50   6848 0 616586 croak "Expecting a reference" if ! length ref $_[0];
98              
99             # be careful not to trigger stringification,
100             # reuse @_ as a scratch-pad
101 6848 100       53181 sprintf '%s%s(0x%x)',
102             ( defined( $_[1] = blessed $_[0]) ? "$_[1]=" : '' ),
103             reftype $_[0],
104             refaddr($_[0]),
105             ;
106             }
107              
108             sub refcount ($) {
109 39009 50   39009 0 60348 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 39009         167824 B::svref_2object($_[0])->REFCNT;
114             }
115              
116             sub serialize ($) {
117 9457     9457 0 52127 local $Storable::canonical = 1;
118 9457         21910 nfreeze($_[0]);
119             }
120              
121             sub scope_guard (&) {
122 8 50   8 0 959 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         37 bless [ $_[0] ], 'DBIx::Class::_Util::ScopeGuard';
127             }
128             {
129             package #
130             DBIx::Class::_Util::ScopeGuard;
131              
132             sub DESTROY {
133 8     8   164 &DBIx::Class::_Util::detected_reinvoked_destructor;
134              
135 8         7 local $@ if DBIx::Class::_ENV_::UNSTABLE_DOLLARAT;
136              
137             eval {
138 8         38 $_[0]->[0]->();
139 8         1277 1;
140 8 50       12 } 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 54255     54255 0 61082 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 54255 50       87422 return 0 unless defined $e;
154              
155 54255         47857 my ($not_blank, $suberror);
156             {
157 54255         45177 local $@;
  54255         46364  
158 54255 100       68217 eval {
159 54255 100       89952 $not_blank = ($e ne '') ? 1 : 0;
160 54252         113725 1;
161             } or $suberror = $@;
162             }
163              
164 54255 100       87971 if (defined $suberror) {
165 3 50       18 if (length (my $class = blessed($e) )) {
166 3         46 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       30 $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 54255         128514 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 59481   66 59481 0 3004552 for keys %$destruction_registry;
216              
217 59481 50       255312 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 59480         168756 weaken( $destruction_registry->{$addr} = $_[0] );
226 59480         365276 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         225 return 1;
242             }
243             }
244             }
245              
246             sub modver_gt_or_eq ($$) {
247 252     252 0 1181 my ($mod, $ver) = @_;
248              
249 252 50 33     2170 croak "Nonsensical module name supplied"
250             if ! defined $mod or ! length $mod;
251              
252 252 50 33     2115 croak "Nonsensical minimum version supplied"
253             if ! defined $ver or $ver =~ /[^0-9\.\_]/;
254              
255 252         733 local $SIG{__WARN__} = sigwarn_silencer( qr/\Qisn't numeric in subroutine entry/ )
256             if SPURIOUS_VERSION_CHECK_WARNINGS;
257              
258 252 50       5044 croak "$mod does not seem to provide a version (perhaps it never loaded)"
259             unless $mod->VERSION;
260              
261 252         778 local $@;
262 252 100       515 eval { $mod->VERSION($ver) } ? 1 : 0;
  252         3380  
263             }
264              
265             sub modver_gt_or_eq_and_lt ($$$) {
266 3     3 0 12156 my ($mod, $v_ge, $v_lt) = @_;
267              
268 3 50 33     32 croak "Nonsensical maximum version supplied"
269             if ! defined $v_lt or $v_lt =~ /[^0-9\.\_]/;
270              
271             return (
272 3 50 66     11 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   2318 no strict 'refs';
  385         779  
  385         38449  
353             B::Deparse->new->coderef2text(\&{$fr->[3]})
354             }),
355             ), 'with_stacktrace');
356             }
357             }
358              
359             1;