Remove useless eval in the leaktracer on 5.8.3+
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / _Util.pm
CommitLineData
b1dbf716 1package # hide from PAUSE
2 DBIx::Class::_Util;
3
399b9455 4use DBIx::Class::StartupCheck; # load es early as we can, usually a noop
5
b1dbf716 6use warnings;
7use strict;
8
750a4ad2 9use constant SPURIOUS_VERSION_CHECK_WARNINGS => ( "$]" < 5.010 ? 1 : 0);
b1dbf716 10
296248c3 11my $mro_recursor_stack;
12
37873f78 13BEGIN {
14 package # hide from pause
15 DBIx::Class::_ENV_;
16
17 use Config;
18
19 use constant {
20
21 # but of course
22 BROKEN_FORK => ($^O eq 'MSWin32') ? 1 : 0,
23
750a4ad2 24 BROKEN_GOTO => ( "$]" < 5.008003 ) ? 1 : 0,
8d73fcd4 25
7bba735d 26 # perl -MScalar::Util=weaken -e 'weaken( $hash{key} = \"value" )'
27 BROKEN_WEAK_SCALARREF_VALUES => ( "$]" < 5.008003 ) ? 1 : 0,
28
37873f78 29 HAS_ITHREADS => $Config{useithreads} ? 1 : 0,
30
bbf6a9a5 31 UNSTABLE_DOLLARAT => ( "$]" < 5.013002 ) ? 1 : 0,
32
db83437e 33 ( map
34 #
35 # the "DBIC_" prefix below is crucial - this is what makes CI pick up
36 # all envvars without further adjusting its scripts
37 # DO NOT CHANGE to the more logical { $_ => !!( $ENV{"DBIC_$_"} ) }
38 #
39 { substr($_, 5) => !!( $ENV{$_} ) }
40 qw(
41 DBIC_SHUFFLE_UNORDERED_RESULTSETS
42 DBIC_ASSERT_NO_INTERNAL_WANTARRAY
43 DBIC_ASSERT_NO_INTERNAL_INDIRECT_CALLS
44 DBIC_STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE
45 DBIC_STRESSTEST_COLUMN_INFO_UNAWARE_STORAGE
46 )
47 ),
f45dc928 48
37873f78 49 IV_SIZE => $Config{ivsize},
00882d2c 50
51 OS_NAME => $^O,
37873f78 52 };
53
750a4ad2 54 if ( "$]" < 5.009_005) {
37873f78 55 require MRO::Compat;
56 constant->import( OLD_MRO => 1 );
296248c3 57
58 #
59 # Yes, I know this is a rather PHP-ish name, but please first read
60 # https://metacpan.org/source/BOBTFISH/MRO-Compat-0.12/lib/MRO/Compat.pm#L363-368
61 #
62 # Even if we are using Class::C3::XS it still won't work, as doing
63 # defined( *{ "SubClass::"->{$_} }{CODE} )
64 # will set pkg_gen to the same value for SubClass and *ALL PARENTS*
65 #
66 *DBIx::Class::_Util::get_real_pkg_gen = sub ($) {
67 require Digest::MD5;
68 require Math::BigInt;
69
70 # the non-assign-unless-there-is-a-hash is deliberate
71 ( $mro_recursor_stack->{cache} || {} )->{$_[0]}{gen} ||= (
72 Math::BigInt->new( '0x' . ( Digest::MD5::md5_hex( join "\0", map {
73
74 ( $mro_recursor_stack->{cache} || {} )->{$_}{methlist} ||= do {
75
76 my $class = $_;
296248c3 77 no strict 'refs';
1c179556 78
79 # RV to be hashed up and turned into a number
80 join "\0", (
81 $class,
296248c3 82 map
1c179556 83 {(
84 # stringification should be sufficient, ignore names/refaddr entirely
85 $_,
86 attributes::get( $_ ),
87 )}
296248c3 88 map
1c179556 89 {(
90 # skip dummy C::C3 helper crefs
91 ! ( ( $Class::C3::MRO{$class} || {} )->{methods}{$_} )
92 and
296248c3 93 (
94 ref(\ "${class}::"->{$_} ) ne 'GLOB'
95 or
96 defined( *{ "${class}::"->{$_} }{CODE} )
97 )
1c179556 98 )
296248c3 99 ? ( \&{"${class}::$_"} )
100 : ()
101 }
102 keys %{ "${class}::" }
1c179556 103 );
296248c3 104 }
d01688cc 105 } (
106
107 @{
108 ( $mro_recursor_stack->{cache} || {} )->{$_[0]}{linear_isa}
109 ||=
110 mro::get_linear_isa($_[0])
111 },
112
113 ((
114 ( $mro_recursor_stack->{cache} || {} )->{$_[0]}{is_universal}
115 ||=
116 mro::is_universal($_[0])
117 ) ? () : @{
118 ( $mro_recursor_stack->{cache} || {} )->{UNIVERSAL}{linear_isa}
119 ||=
120 mro::get_linear_isa("UNIVERSAL")
121 } ),
122
123 ) ) ) )
296248c3 124 );
125 };
37873f78 126 }
127 else {
128 require mro;
129 constant->import( OLD_MRO => 0 );
296248c3 130 *DBIx::Class::_Util::get_real_pkg_gen = \&mro::get_pkg_gen;
37873f78 131 }
4b1b44c1 132
133 # Both of these are no longer used for anything. However bring
134 # them back after they were purged in 08a8d8f1, as there appear
135 # to be outfits with *COPY PASTED* pieces of lib/DBIx/Class/Storage/*
136 # in their production codebases. There is no point in breaking these
137 # if whatever they used actually continues to work
138 my $warned;
139 my $sigh = sub {
140
141 require Carp;
142 my $cluck = "The @{[ (caller(1))[3] ]} constant is no more - adjust your code" . Carp::longmess();
143
144 warn $cluck unless $warned->{$cluck}++;
145
146 0;
147 };
148 sub DBICTEST () { &$sigh }
149 sub PEEPEENESS () { &$sigh }
37873f78 150}
151
841efcb3 152# FIXME - this is not supposed to be here
153# Carp::Skip to the rescue soon
154use DBIx::Class::Carp '^DBIx::Class|^DBICTest';
155
d7d45bdc 156use B ();
841efcb3 157use Carp 'croak';
d7d45bdc 158use Storable 'nfreeze';
3d56e026 159use Scalar::Util qw(weaken blessed reftype refaddr);
e85eb407 160use Sub::Quote qw(qsub);
514b84f6 161use Sub::Name ();
296248c3 162use attributes ();
7f9a3f70 163
1c30a2e4 164# Already correctly prototyped: perlbrew exec perl -MStorable -e 'warn prototype \&Storable::dclone'
165BEGIN { *deep_clone = \&Storable::dclone }
166
b1dbf716 167use base 'Exporter';
3705e3b2 168our @EXPORT_OK = qw(
d634850b 169 sigwarn_silencer modver_gt_or_eq modver_gt_or_eq_and_lt
77c3a5dc 170 fail_on_internal_wantarray fail_on_internal_call
296248c3 171 refdesc refcount hrefaddr set_subname describe_class_methods
ddcc02d1 172 scope_guard detected_reinvoked_destructor
10be570e 173 is_exception dbic_internal_try visit_namespaces
174 quote_sub qsub perlstring serialize deep_clone dump_value uniq
439a7283 175 parent_dir mkdir_p
facd0e8e 176 UNRESOLVABLE_CONDITION
3705e3b2 177);
052a832c 178
facd0e8e 179use constant UNRESOLVABLE_CONDITION => \ '1 = 0';
180
e85eb407 181BEGIN {
140bcb6a 182 # add preliminary attribute support
183 # FIXME FIXME FIXME
184 # To be revisited when Moo with proper attr support ships
e85eb407 185 Sub::Quote->VERSION(2.002);
186}
187# Override forcing no_defer, and adding naming consistency checks
188sub quote_sub {
189 Carp::confess( "Anonymous quoting not supported by the DBIC sub_quote override - supply a sub name" ) if
190 @_ < 2
191 or
192 ! defined $_[1]
193 or
194 length ref $_[1]
195 ;
196
197 Carp::confess( "The DBIC sub_quote override expects sub name '$_[0]' to be fully qualified" )
198 unless $_[0] =~ /::/;
199
200 Carp::confess( "The DBIC sub_quote override expects the sub name '$_[0]' to match the supplied 'package' argument" ) if
201 $_[3]
202 and
203 defined $_[3]->{package}
204 and
205 index( $_[0], $_[3]->{package} ) != 0
206 ;
207
208 my @caller = caller(0);
209 my $sq_opts = {
210 package => $caller[0],
211 hints => $caller[8],
212 warning_bits => $caller[9],
213 hintshash => $caller[10],
214 %{ $_[3] || {} },
215
216 # explicitly forced for everything
217 no_defer => 1,
218 };
219
220 my $cref = Sub::Quote::quote_sub( $_[0], $_[1], $_[2]||{}, $sq_opts );
140bcb6a 221
222 # FIXME FIXME FIXME
223 # To be revisited when Moo with proper attr support ships
224 if(
225 # external application does not work on things like :prototype(...), :lvalue, etc
226 my @attrs = grep {
227 $_ !~ /^[a-z]/
228 or
229 Carp::confess( "The DBIC sub_quote override does not support applying of reserved attribute '$_'" )
230 } @{ $sq_opts->{attributes} || []}
231 ) {
232 Carp::confess( "The DBIC sub_quote override does not allow mixing 'attributes' with 'no_install'" )
233 if $sq_opts->{no_install};
234
235 # might be different from $sq_opts->{package};
236 my ($install_into) = $_[0] =~ /(.+)::[^:]+$/;
237
238 attributes->import( $install_into, $cref, @attrs );
239 }
240
241 $cref;
e85eb407 242}
243
bf302897 244sub sigwarn_silencer ($) {
052a832c 245 my $pattern = shift;
246
247 croak "Expecting a regexp" if ref $pattern ne 'Regexp';
248
249 my $orig_sig_warn = $SIG{__WARN__} || sub { CORE::warn(@_) };
250
251 return sub { &$orig_sig_warn unless $_[0] =~ $pattern };
252}
b1dbf716 253
01b25f12 254sub perlstring ($) { q{"}. quotemeta( shift ). q{"} };
255
3d56e026 256sub hrefaddr ($) { sprintf '0x%x', &refaddr||0 }
8433421f 257
258sub refdesc ($) {
259 croak "Expecting a reference" if ! length ref $_[0];
260
261 # be careful not to trigger stringification,
262 # reuse @_ as a scratch-pad
263 sprintf '%s%s(0x%x)',
264 ( defined( $_[1] = blessed $_[0]) ? "$_[1]=" : '' ),
265 reftype $_[0],
3d56e026 266 refaddr($_[0]),
8433421f 267 ;
268}
bf302897 269
270sub refcount ($) {
dac7972a 271 croak "Expecting a reference" if ! length ref $_[0];
272
dac7972a 273 # No tempvars - must operate on $_[0], otherwise the pad
274 # will count as an extra ref
275 B::svref_2object($_[0])->REFCNT;
276}
277
10be570e 278sub visit_namespaces {
279 my $args = { (ref $_[0]) ? %{$_[0]} : @_ };
280
281 my $visited_count = 1;
282
283 # A package and a namespace are subtly different things
284 $args->{package} ||= 'main';
285 $args->{package} = 'main' if $args->{package} =~ /^ :: (?: main )? $/x;
286 $args->{package} =~ s/^:://;
287
288 if ( $args->{action}->($args->{package}) ) {
289 my $ns =
290 ( ($args->{package} eq 'main') ? '' : $args->{package} )
291 .
292 '::'
293 ;
294
295 $visited_count += visit_namespaces( %$args, package => $_ ) for
296 grep
297 # this happens sometimes on %:: traversal
298 { $_ ne '::main' }
299 map
300 { $_ =~ /^(.+?)::$/ ? "$ns$1" : () }
301 do { no strict 'refs'; keys %$ns }
302 ;
303 }
304
305 $visited_count;
306}
307
514b84f6 308# FIXME In another life switch this to a polyfill like the one in namespace::clean
309sub set_subname ($$) {
310
311 # fully qualify name
312 splice @_, 0, 1, caller(0) . "::$_[0]"
313 if $_[0] !~ /::|'/;
314
315 &Sub::Name::subname;
316}
317
b34d9331 318sub serialize ($) {
b34d9331 319 local $Storable::canonical = 1;
d7d45bdc 320 nfreeze($_[0]);
b34d9331 321}
322
10be570e 323sub uniq {
324 my( %seen, $seen_undef, $numeric_preserving_copy );
325 grep { not (
326 defined $_
327 ? $seen{ $numeric_preserving_copy = $_ }++
328 : $seen_undef++
329 ) } @_;
330}
331
2d5ac3cf 332my $dd_obj;
8fc4291e 333sub dump_value ($) {
334 local $Data::Dumper::Indent = 1
335 unless defined $Data::Dumper::Indent;
336
2d5ac3cf 337 my $dump_str = (
8fc4291e 338 $dd_obj
339 ||=
340 do {
341 require Data::Dumper;
342 my $d = Data::Dumper->new([])
343 ->Purity(0)
344 ->Pad('')
345 ->Useqq(1)
346 ->Terse(1)
347 ->Freezer('')
348 ->Quotekeys(0)
349 ->Bless('bless')
350 ->Pair(' => ')
351 ->Sortkeys(1)
352 ->Deparse(1)
353 ;
354
355 $d->Sparseseen(1) if modver_gt_or_eq (
356 'Data::Dumper', '2.136'
357 );
358
359 $d;
360 }
361 )->Values([$_[0]])->Dump;
362
363 $dd_obj->Reset->Values([]);
364
365 $dump_str;
366}
367
bbf6a9a5 368sub scope_guard (&) {
369 croak 'Calling scope_guard() in void context makes no sense'
370 if ! defined wantarray;
371
372 # no direct blessing of coderefs - DESTROY is buggy on those
373 bless [ $_[0] ], 'DBIx::Class::_Util::ScopeGuard';
374}
375{
376 package #
377 DBIx::Class::_Util::ScopeGuard;
378
379 sub DESTROY {
380 &DBIx::Class::_Util::detected_reinvoked_destructor;
381
382 local $@ if DBIx::Class::_ENV_::UNSTABLE_DOLLARAT;
383
384 eval {
385 $_[0]->[0]->();
386 1;
118b2c36 387 }
388 or
389 Carp::cluck(
390 "Execution of scope guard $_[0] resulted in the non-trappable exception:\n\n$@"
391 );
bbf6a9a5 392 }
393}
394
395
841efcb3 396sub is_exception ($) {
397 my $e = $_[0];
398
35cf7d1a 399 # FIXME
a0414138 400 # this is not strictly correct - an eval setting $@ to undef
401 # is *not* the same as an eval setting $@ to ''
402 # but for the sake of simplicity assume the following for
403 # the time being
404 return 0 unless defined $e;
405
841efcb3 406 my ($not_blank, $suberror);
407 {
5c33c8be 408 local $SIG{__DIE__} if $SIG{__DIE__};
841efcb3 409 local $@;
410 eval {
d52c4a75 411 # The ne() here is deliberate - a plain length($e), or worse "$e" ne
412 # will entirely obviate the need for the encolsing eval{}, as the
413 # condition we guard against is a missing fallback overload
414 $not_blank = ( $e ne '' );
841efcb3 415 1;
416 } or $suberror = $@;
417 }
418
419 if (defined $suberror) {
420 if (length (my $class = blessed($e) )) {
421 carp_unique( sprintf(
9bea2000 422 'External exception class %s implements partial (broken) overloading '
423 . 'preventing its instances from being used in simple ($x eq $y) '
841efcb3 424 . 'comparisons. Given Perl\'s "globally cooperative" exception '
425 . 'handling this type of brokenness is extremely dangerous on '
426 . 'exception objects, as it may (and often does) result in silent '
427 . '"exception substitution". DBIx::Class tries to work around this '
428 . 'as much as possible, but other parts of your software stack may '
429 . 'not be even aware of this. Please submit a bugreport against the '
430 . 'distribution containing %s and in the meantime apply a fix similar '
431 . 'to the one shown at %s, in order to ensure your exception handling '
432 . 'is saner application-wide. What follows is the actual error text '
433 . "as generated by Perl itself:\n\n%s\n ",
9bea2000 434 $class,
841efcb3 435 $class,
436 'http://v.gd/DBIC_overload_tempfix/',
437 $suberror,
438 ));
439
440 # workaround, keeps spice flowing
d52c4a75 441 $not_blank = !!( length $e );
841efcb3 442 }
443 else {
444 # not blessed yet failed the 'ne'... this makes 0 sense...
445 # just throw further
446 die $suberror
447 }
448 }
84e4e006 449 elsif (
450 # a ref evaluating to '' is definitively a "null object"
451 ( not $not_blank )
452 and
453 length( my $class = ref $e )
454 ) {
455 carp_unique( sprintf(
456 "Objects of external exception class '%s' stringify to '' (the "
457 . 'empty string), implementing the so called null-object-pattern. '
458 . 'Given Perl\'s "globally cooperative" exception handling using this '
459 . 'class of exceptions is extremely dangerous, as it may (and often '
460 . 'does) result in silent discarding of errors. DBIx::Class tries to '
461 . 'work around this as much as possible, but other parts of your '
462 . 'software stack may not be even aware of the problem. Please submit '
35cf7d1a 463 . 'a bugreport against the distribution containing %s',
84e4e006 464
465 ($class) x 2,
466 ));
467
468 $not_blank = 1;
469 }
841efcb3 470
471 return $not_blank;
472}
473
3d56e026 474{
ddcc02d1 475 my $callstack_state;
476
477 # Recreate the logic of try(), while reusing the catch()/finally() as-is
478 #
479 # FIXME: We need to move away from Try::Tiny entirely (way too heavy and
480 # yes, shows up ON TOP of profiles) but this is a batle for another maint
481 sub dbic_internal_try (&;@) {
482
483 my $try_cref = shift;
484 my $catch_cref = undef; # apparently this is a thing... https://rt.perl.org/Public/Bug/Display.html?id=119311
485
486 for my $arg (@_) {
487
488 if( ref($arg) eq 'Try::Tiny::Catch' ) {
489
490 croak 'dbic_internal_try() may not be followed by multiple catch() blocks'
491 if $catch_cref;
492
493 $catch_cref = $$arg;
494 }
495 elsif ( ref($arg) eq 'Try::Tiny::Finally' ) {
496 croak 'dbic_internal_try() does not support finally{}';
497 }
498 else {
499 croak(
500 'dbic_internal_try() encountered an unexpected argument '
501 . "'@{[ defined $arg ? $arg : 'UNDEF' ]}' - perhaps "
502 . 'a missing semi-colon before or ' # trailing space important
503 );
504 }
505 }
506
507 my $wantarray = wantarray;
508 my $preexisting_exception = $@;
509
510 my @ret;
511 my $all_good = eval {
512 $@ = $preexisting_exception;
513
514 local $callstack_state->{in_internal_try} = 1
515 unless $callstack_state->{in_internal_try};
516
517 # always unset - someone may have snuck it in
5c33c8be 518 local $SIG{__DIE__} if $SIG{__DIE__};
ddcc02d1 519
520 if( $wantarray ) {
521 @ret = $try_cref->();
522 }
523 elsif( defined $wantarray ) {
524 $ret[0] = $try_cref->();
525 }
526 else {
527 $try_cref->();
528 }
529
530 1;
531 };
532
533 my $exception = $@;
534 $@ = $preexisting_exception;
535
536 if ( $all_good ) {
537 return $wantarray ? @ret : $ret[0]
538 }
539 elsif ( $catch_cref ) {
540 for ( $exception ) {
541 return $catch_cref->($exception);
542 }
543 }
544
545 return;
546 }
547
548 sub in_internal_try { !! $callstack_state->{in_internal_try} }
549}
550
551{
3d56e026 552 my $destruction_registry = {};
553
04c1a070 554 sub DBIx::Class::__Util_iThreads_handler__::CLONE {
d098704f 555 %$destruction_registry = map {
556 (defined $_)
557 ? ( refaddr($_) => $_ )
558 : ()
559 } values %$destruction_registry;
d52fc26d 560
d098704f 561 weaken($_) for values %$destruction_registry;
29211e03 562
d52fc26d 563 # Dummy NEXTSTATE ensuring the all temporaries on the stack are garbage
564 # collected before leaving this scope. Depending on the code above, this
565 # may very well be just a preventive measure guarding future modifications
566 undef;
3d56e026 567 }
568
569 # This is almost invariably invoked from within DESTROY
570 # throwing exceptions won't work
e1d9e578 571 sub detected_reinvoked_destructor {
3d56e026 572
573 # quick "garbage collection" pass - prevents the registry
574 # from slowly growing with a bunch of undef-valued keys
575 defined $destruction_registry->{$_} or delete $destruction_registry->{$_}
576 for keys %$destruction_registry;
577
e1d9e578 578 if (! length ref $_[0]) {
579 printf STDERR '%s() expects a blessed reference %s',
3d56e026 580 (caller(0))[3],
581 Carp::longmess,
582 ;
583 return undef; # don't know wtf to do
584 }
e1d9e578 585 elsif (! defined $destruction_registry->{ my $addr = refaddr($_[0]) } ) {
3d56e026 586 weaken( $destruction_registry->{$addr} = $_[0] );
587 return 0;
588 }
589 else {
590 carp_unique ( sprintf (
591 'Preventing *MULTIPLE* DESTROY() invocations on %s - an *EXTREMELY '
592 . 'DANGEROUS* condition which is *ALMOST CERTAINLY GLOBAL* within your '
593 . 'application, affecting *ALL* classes without active protection against '
594 . 'this. Diagnose and fix the root cause ASAP!!!%s',
595 refdesc $_[0],
596 ( ( $INC{'Devel/StackTrace.pm'} and ! do { local $@; eval { Devel::StackTrace->VERSION(2) } } )
597 ? " (likely culprit Devel::StackTrace\@@{[ Devel::StackTrace->VERSION ]} found in %INC, http://is.gd/D_ST_refcap)"
598 : ''
599 )
600 ));
601
602 return 1;
603 }
604 }
605}
606
7302b3e0 607my $module_name_rx = qr/ \A [A-Z_a-z] [0-9A-Z_a-z]* (?: :: [0-9A-Z_a-z]+ )* \z /x;
608my $ver_rx = qr/ \A [0-9]+ (?: \. [0-9]+ )* (?: \_ [0-9]+ )* \z /x;
609
bf302897 610sub modver_gt_or_eq ($$) {
b1dbf716 611 my ($mod, $ver) = @_;
612
613 croak "Nonsensical module name supplied"
7302b3e0 614 if ! defined $mod or $mod !~ $module_name_rx;
b1dbf716 615
616 croak "Nonsensical minimum version supplied"
7302b3e0 617 if ! defined $ver or $ver !~ $ver_rx;
618
619 no strict 'refs';
620 my $ver_cache = ${"${mod}::__DBIC_MODULE_VERSION_CHECKS__"} ||= ( $mod->VERSION
621 ? {}
622 : croak "$mod does not seem to provide a version (perhaps it never loaded)"
623 );
624
625 ! defined $ver_cache->{$ver}
626 and
627 $ver_cache->{$ver} = do {
b1dbf716 628
7302b3e0 629 local $SIG{__WARN__} = sigwarn_silencer( qr/\Qisn't numeric in subroutine entry/ )
630 if SPURIOUS_VERSION_CHECK_WARNINGS;
b1dbf716 631
5c33c8be 632 local $SIG{__DIE__} if $SIG{__DIE__};
7302b3e0 633 local $@;
7302b3e0 634 eval { $mod->VERSION($ver) } ? 1 : 0;
635 };
56270bba 636
7302b3e0 637 $ver_cache->{$ver};
b1dbf716 638}
639
d634850b 640sub modver_gt_or_eq_and_lt ($$$) {
641 my ($mod, $v_ge, $v_lt) = @_;
642
643 croak "Nonsensical maximum version supplied"
7302b3e0 644 if ! defined $v_lt or $v_lt !~ $ver_rx;
d634850b 645
646 return (
647 modver_gt_or_eq($mod, $v_ge)
648 and
649 ! modver_gt_or_eq($mod, $v_lt)
650 ) ? 1 : 0;
651}
652
296248c3 653{
654 # FIXME - should be a private my(), but I'm too uncertain whether
655 # all bases are covered
656 our $describe_class_query_cache;
657
658 sub describe_class_methods {
1cf2ad8b 659 my ($class, $requested_mro) = @_;
296248c3 660
661 croak "Expecting a class name"
5e67be26 662 if not defined $class or $class !~ $module_name_rx;
296248c3 663
1cf2ad8b 664 $requested_mro ||= mro::get_mro($class);
665
666 # mro::set_mro() does not bump pkg_gen - WHAT THE FUCK?!
667 my $query_cache_key = "$class|$requested_mro";
668
669 my $stack_cache_key =
670 ( mro::get_mro($class) eq $requested_mro )
671 ? $class
672 : $query_cache_key
673 ;
674
296248c3 675 # use a cache on old MRO, since while we are recursing in this function
676 # nothing can possibly change (the speedup is immense)
677 # (yes, people could be tie()ing the stash and adding methods on access
678 # but there is a limit to how much crazy can be supported here)
679 #
680 # we use the cache for linear_isa lookups on new MRO as well - it adds
681 # a *tiny* speedup, and simplifies the code a lot
682 #
683 local $mro_recursor_stack->{cache} = {}
684 unless $mro_recursor_stack->{cache};
685
686 my $my_gen = 0;
687
d01688cc 688 $my_gen += get_real_pkg_gen($_) for ( my @full_ISA = (
689
690 @{
1cf2ad8b 691 $mro_recursor_stack->{cache}{$stack_cache_key}{linear_isa}
296248c3 692 ||=
1cf2ad8b 693 mro::get_linear_isa($class, $requested_mro)
d01688cc 694 },
695
696 ((
697 $mro_recursor_stack->{cache}{$class}{is_universal}
698 ||=
699 mro::is_universal($class)
700 ) ? () : @{
701 $mro_recursor_stack->{cache}{UNIVERSAL}{linear_isa}
702 ||=
703 mro::get_linear_isa("UNIVERSAL")
704 }),
705
706 ));
296248c3 707
1cf2ad8b 708 my $slot = $describe_class_query_cache->{$query_cache_key} ||= {};
296248c3 709
710 unless ( ($slot->{cumulative_gen}||0) == $my_gen ) {
711
d01688cc 712 # remove ourselves from ISA
713 shift @full_ISA;
714
296248c3 715 # reset
716 %$slot = (
717 class => $class,
d01688cc 718 isa => [
1cf2ad8b 719 @{ $mro_recursor_stack->{cache}{$stack_cache_key}{linear_isa} }
720 [ 1 .. $#{$mro_recursor_stack->{cache}{$stack_cache_key}{linear_isa}} ]
d01688cc 721 ],
296248c3 722 mro => {
1cf2ad8b 723 type => $requested_mro,
724 is_c3 => ( ($requested_mro eq 'c3') ? 1 : 0 ),
296248c3 725 },
726 cumulative_gen => $my_gen,
727 );
296248c3 728
296248c3 729 # ensure the cache is populated for the parents, code below can then
730 # efficiently operate over the query_cache directly
d01688cc 731 describe_class_methods($_) for reverse @full_ISA;
296248c3 732
296248c3 733 no strict 'refs';
734
735 # combine full ISA-order inherited and local method list into a
736 # "shadowing stack"
737
738 (
085dbdd6 739 unshift @{ $slot->{methods}{$_->{name}} }, $_
296248c3 740
741 and
742
085dbdd6 743 (
744 $_->{via_class} ne $class
745 or
746 $slot->{methods_defined_in_class}{$_->{name}} = $_
747 )
296248c3 748
749 and
750
751 @{ $slot->{methods}{$_->{name}} } > 1
752
753 and
754
755 $slot->{methods_with_supers}{$_->{name}} = $slot->{methods}{$_->{name}}
756
757 ) for (
758
d01688cc 759 # what describe_class_methods for @full_ISA produced above
085dbdd6 760 ( map { values %{
761 $describe_class_query_cache->{$_}{methods_defined_in_class} || {}
1cf2ad8b 762 } } map { "$_|" . mro::get_mro($_) } reverse @full_ISA ),
296248c3 763
764 # our own non-cleaned subs + their attributes
765 ( map {
766 (
1c179556 767 # need to account for dummy helper crefs under OLD_MRO
296248c3 768 (
1c179556 769 ! DBIx::Class::_ENV_::OLD_MRO
296248c3 770 or
1c179556 771 ! ( ( $Class::C3::MRO{$class} || {} )->{methods}{$_} )
296248c3 772 )
773 and
1c179556 774 # these 2 OR-ed checks are sufficient for 5.10+
296248c3 775 (
1c179556 776 ref(\ "${class}::"->{$_} ) ne 'GLOB'
296248c3 777 or
1c179556 778 defined( *{ "${class}::"->{$_} }{CODE} )
296248c3 779 )
780 ) ? {
781 via_class => $class,
782 name => $_,
5e67be26 783 attributes => {
784 map { $_ => 1 } attributes::get( \&{"${class}::${_}"} )
785 },
296248c3 786 }
787 : ()
788 } keys %{"${class}::"} )
789 );
790
791
792 # recalculate the pkg_gen on newer perls under Taint mode,
793 # because of shit like:
794 # perl -T -Mmro -e 'package Foo; sub bar {}; defined( *{ "Foo::"->{bar}}{CODE} ) and warn mro::get_pkg_gen("Foo") for (1,2,3)'
795 #
796 if (
797 ! DBIx::Class::_ENV_::OLD_MRO
798 and
799 ${^TAINT}
800 ) {
801
802 $slot->{cumulative_gen} = 0;
803 $slot->{cumulative_gen} += get_real_pkg_gen($_)
d01688cc 804 for $class, @full_ISA;
296248c3 805 }
806 }
807
808 # RV
809 +{ %$slot };
810 }
811}
812
e3be2b6f 813
814#
815# Why not just use some higher-level module or at least File::Spec here?
816# Because:
817# 1) This is a *very* rarely used function, and the deptree is large
818# enough already as it is
819#
820# 2) (more importantly) Our tooling is utter shit in this area. There
821# is no comprehensive support for UNC paths in PathTools and there
822# are also various small bugs in representation across different
823# path-manipulation CPAN offerings.
824#
825# Since this routine is strictly used for logical path processing (it
826# *must* be able to work with not-yet-existing paths), use this seemingly
827# simple but I *think* complete implementation to feed to other consumers
828#
829# If bugs are ever uncovered in this routine, *YOU ARE URGED TO RESIST*
830# the impulse to bring in an external dependency. During runtime there
831# is exactly one spot that could potentially maybe once in a blue moon
832# use this function. Keep it lean.
833#
834sub parent_dir ($) {
835 ( $_[0] =~ m{ [\/\\] ( \.{0,2} ) ( [\/\\]* ) \z }x )
836 ? (
837 $_[0]
838 .
839 ( ( length($1) and ! length($2) ) ? '/' : '' )
840 .
841 '../'
842 )
843 : (
844 require File::Spec
845 and
846 File::Spec->catpath (
847 ( File::Spec->splitpath( "$_[0]" ) )[0,1],
848 '/',
849 )
850 )
851 ;
852}
853
439a7283 854sub mkdir_p ($) {
855 require File::Path;
856 # do not ask for a recent version, use 1.x API calls
857 File::Path::mkpath([ "$_[0]" ]); # File::Path does not like objects
858}
859
e3be2b6f 860
a9da9b6a 861{
862 my $list_ctx_ok_stack_marker;
863
e89c7968 864 sub fail_on_internal_wantarray () {
a9da9b6a 865 return if $list_ctx_ok_stack_marker;
866
867 if (! defined wantarray) {
868 croak('fail_on_internal_wantarray() needs a tempvar to save the stack marker guard');
869 }
870
871 my $cf = 1;
821edc09 872 while ( ( (CORE::caller($cf+1))[3] || '' ) =~ / :: (?:
a9da9b6a 873
874 # these are public API parts that alter behavior on wantarray
875 search | search_related | slice | search_literal
876
877 |
878
879 # these are explicitly prefixed, since we only recognize them as valid
880 # escapes when they come from the guts of CDBICompat
881 CDBICompat .*? :: (?: search_where | retrieve_from_sql | retrieve_all )
882
883 ) $/x ) {
884 $cf++;
885 }
886
e89c7968 887 my ($fr, $want, $argdesc);
888 {
889 package DB;
821edc09 890 $fr = [ CORE::caller($cf) ];
891 $want = ( CORE::caller($cf-1) )[5];
e89c7968 892 $argdesc = ref $DB::args[0]
893 ? DBIx::Class::_Util::refdesc($DB::args[0])
894 : 'non '
895 ;
896 };
897
a9da9b6a 898 if (
e89c7968 899 $want and $fr->[0] =~ /^(?:DBIx::Class|DBICx::)/
a9da9b6a 900 ) {
a9da9b6a 901 DBIx::Class::Exception->throw( sprintf (
e89c7968 902 "Improper use of %s instance in list context at %s line %d\n\n Stacktrace starts",
903 $argdesc, @{$fr}[1,2]
a9da9b6a 904 ), 'with_stacktrace');
905 }
906
d098704f 907 weaken( $list_ctx_ok_stack_marker = my $mark = [] );
908
a9da9b6a 909 $mark;
910 }
911}
912
77c3a5dc 913sub fail_on_internal_call {
914 my ($fr, $argdesc);
915 {
916 package DB;
821edc09 917 $fr = [ CORE::caller(1) ];
77c3a5dc 918 $argdesc = ref $DB::args[0]
919 ? DBIx::Class::_Util::refdesc($DB::args[0])
e5053694 920 : ( $DB::args[0] . '' )
77c3a5dc 921 ;
922 };
923
3b020224 924 my @fr2;
925 # need to make allowance for a proxy-yet-direct call
926 my $check_fr = (
927 $fr->[0] eq 'DBIx::Class::ResultSourceProxy'
928 and
929 @fr2 = (CORE::caller(2))
930 and
931 (
932 ( $fr->[3] =~ /([^:])+$/ )[0]
933 eq
934 ( $fr2[3] =~ /([^:])+$/ )[0]
935 )
936 )
937 ? \@fr2
938 : $fr
939 ;
940
77c3a5dc 941 if (
942 $argdesc
943 and
3b020224 944 $check_fr->[0] =~ /^(?:DBIx::Class|DBICx::)/
77c3a5dc 945 and
3b020224 946 $check_fr->[1] !~ /\b(?:CDBICompat|ResultSetProxy)\b/ # no point touching there
77c3a5dc 947 ) {
948 DBIx::Class::Exception->throw( sprintf (
e5053694 949 "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",
77c3a5dc 950 $fr->[3], $argdesc, @{$fr}[1,2], ( $fr->[6] || do {
951 require B::Deparse;
952 no strict 'refs';
953 B::Deparse->new->coderef2text(\&{$fr->[3]})
954 }),
955 ), 'with_stacktrace');
956 }
957}
958
b1dbf716 9591;