line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package # hide from the pauses |
2
|
|
|
|
|
|
|
DBIx::Class::ResultSource::RowParser; |
3
|
|
|
|
|
|
|
|
4
|
436
|
|
|
436
|
|
3934
|
use strict; |
|
436
|
|
|
|
|
1464
|
|
|
436
|
|
|
|
|
12993
|
|
5
|
436
|
|
|
436
|
|
2660
|
use warnings; |
|
436
|
|
|
|
|
1387
|
|
|
436
|
|
|
|
|
12927
|
|
6
|
|
|
|
|
|
|
|
7
|
436
|
|
|
436
|
|
2616
|
use base 'DBIx::Class'; |
|
436
|
|
|
|
|
1524
|
|
|
436
|
|
|
|
|
59251
|
|
8
|
|
|
|
|
|
|
|
9
|
419
|
|
|
419
|
|
3737
|
use Try::Tiny; |
|
419
|
|
|
|
|
1466
|
|
|
419
|
|
|
|
|
27605
|
|
10
|
419
|
|
|
419
|
|
3240
|
use List::Util qw(first max); |
|
419
|
|
|
|
|
1409
|
|
|
419
|
|
|
|
|
32524
|
|
11
|
|
|
|
|
|
|
|
12
|
419
|
|
|
|
|
38558
|
use DBIx::Class::ResultSource::RowParser::Util qw( |
13
|
|
|
|
|
|
|
assemble_simple_parser |
14
|
|
|
|
|
|
|
assemble_collapsing_parser |
15
|
419
|
|
|
419
|
|
185343
|
); |
|
419
|
|
|
|
|
1454
|
|
16
|
|
|
|
|
|
|
|
17
|
381
|
|
|
381
|
|
3360
|
use namespace::clean; |
|
381
|
|
|
|
|
1278
|
|
|
381
|
|
|
|
|
2881
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Accepts one or more relationships for the current source and returns an |
20
|
|
|
|
|
|
|
# array of column names for each of those relationships. Column names are |
21
|
|
|
|
|
|
|
# prefixed relative to the current source, in accordance with where they appear |
22
|
|
|
|
|
|
|
# in the supplied relationships. |
23
|
|
|
|
|
|
|
sub _resolve_prefetch { |
24
|
966
|
|
|
966
|
|
2847
|
my ($self, $pre, $alias, $alias_map, $order, $pref_path) = @_; |
25
|
966
|
|
100
|
|
|
3031
|
$pref_path ||= []; |
26
|
|
|
|
|
|
|
|
27
|
966
|
100
|
100
|
|
|
5765
|
if (not defined $pre or not length $pre) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
28
|
99
|
|
|
|
|
350
|
return (); |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
elsif( ref $pre eq 'ARRAY' ) { |
31
|
|
|
|
|
|
|
return |
32
|
362
|
|
|
|
|
974
|
map { $self->_resolve_prefetch( $_, $alias, $alias_map, $order, [ @$pref_path ] ) } |
|
422
|
|
|
|
|
2568
|
|
33
|
|
|
|
|
|
|
@$pre; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
elsif( ref $pre eq 'HASH' ) { |
36
|
|
|
|
|
|
|
my @ret = |
37
|
|
|
|
|
|
|
map { |
38
|
98
|
|
|
|
|
315
|
$self->_resolve_prefetch($_, $alias, $alias_map, $order, [ @$pref_path ] ), |
39
|
|
|
|
|
|
|
$self->related_source($_)->_resolve_prefetch( |
40
|
97
|
|
|
|
|
517
|
$pre->{$_}, "${alias}.$_", $alias_map, $order, [ @$pref_path, $_] ) |
41
|
|
|
|
|
|
|
} keys %$pre; |
42
|
98
|
|
|
|
|
672
|
return @ret; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
elsif( ref $pre ) { |
45
|
1
|
|
|
|
|
4
|
$self->throw_exception( |
46
|
|
|
|
|
|
|
"don't know how to resolve prefetch reftype ".ref($pre)); |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
else { |
49
|
411
|
|
|
|
|
820
|
my $p = $alias_map; |
50
|
411
|
|
|
|
|
1567
|
$p = $p->{$_} for (@$pref_path, $pre); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
$self->throw_exception ( |
53
|
|
|
|
|
|
|
"Unable to resolve prefetch '$pre' - join alias map does not contain an entry for path: " |
54
|
|
|
|
|
|
|
. join (' -> ', @$pref_path, $pre) |
55
|
411
|
50
|
33
|
|
|
1640
|
) if (ref $p->{-join_aliases} ne 'ARRAY' or not @{$p->{-join_aliases}} ); |
|
411
|
|
|
|
|
1611
|
|
56
|
|
|
|
|
|
|
|
57
|
411
|
|
|
|
|
1101
|
my $as = shift @{$p->{-join_aliases}}; |
|
411
|
|
|
|
|
1080
|
|
58
|
|
|
|
|
|
|
|
59
|
411
|
|
|
|
|
1445
|
my $rel_info = $self->relationship_info( $pre ); |
60
|
411
|
50
|
|
|
|
1194
|
$self->throw_exception( $self->source_name . " has no such relationship '$pre'" ) |
61
|
|
|
|
|
|
|
unless $rel_info; |
62
|
|
|
|
|
|
|
|
63
|
411
|
100
|
|
|
|
2024
|
my $as_prefix = ($alias =~ /^.*?\.(.+)$/ ? $1.'.' : ''); |
64
|
|
|
|
|
|
|
|
65
|
411
|
|
|
|
|
1410
|
return map { [ "${as}.$_", "${as_prefix}${pre}.$_", ] } |
|
1849
|
|
|
|
|
8794
|
|
66
|
|
|
|
|
|
|
$self->related_source($pre)->columns; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# Takes an arrayref of {as} dbic column aliases and the collapse and select |
71
|
|
|
|
|
|
|
# attributes from the same $rs (the selector requirement is a temporary |
72
|
|
|
|
|
|
|
# workaround... I hope), and returns a coderef capable of: |
73
|
|
|
|
|
|
|
# my $me_pref_clps = $coderef->([$rs->cursor->next/all]) |
74
|
|
|
|
|
|
|
# Where the $me_pref_clps arrayref is the future argument to inflate_result() |
75
|
|
|
|
|
|
|
# |
76
|
|
|
|
|
|
|
# For an example of this coderef in action (and to see its guts) look at |
77
|
|
|
|
|
|
|
# t/resultset/rowparser_internals.t |
78
|
|
|
|
|
|
|
# |
79
|
|
|
|
|
|
|
# This is a huge performance win, as we call the same code for every row |
80
|
|
|
|
|
|
|
# returned from the db, thus avoiding repeated method lookups when traversing |
81
|
|
|
|
|
|
|
# relationships |
82
|
|
|
|
|
|
|
# |
83
|
|
|
|
|
|
|
# Also since the coderef is completely stateless (the returned structure is |
84
|
|
|
|
|
|
|
# always fresh on every new invocation) this is a very good opportunity for |
85
|
|
|
|
|
|
|
# memoization if further speed improvements are needed |
86
|
|
|
|
|
|
|
# |
87
|
|
|
|
|
|
|
# The way we construct this coderef is somewhat fugly, although the result is |
88
|
|
|
|
|
|
|
# really worth it. The final coderef does not perform any kind of recursion - |
89
|
|
|
|
|
|
|
# the entire nested structure constructor is rolled out into a single scope. |
90
|
|
|
|
|
|
|
# |
91
|
|
|
|
|
|
|
# In any case - the output of this thing is meticulously micro-tested, so |
92
|
|
|
|
|
|
|
# any sort of adjustment/rewrite should be relatively easy (fsvo relatively) |
93
|
|
|
|
|
|
|
# |
94
|
|
|
|
|
|
|
sub _mk_row_parser { |
95
|
|
|
|
|
|
|
# $args and $attrs are separated to delineate what is core collapser stuff and |
96
|
|
|
|
|
|
|
# what is dbic $rs specific |
97
|
234
|
|
|
235
|
|
859
|
my ($self, $args, $attrs) = @_; |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
die "HRI without pruning makes zero sense" |
100
|
234
|
50
|
66
|
|
|
1163
|
if ( $args->{hri_style} && ! $args->{prune_null_branches} ); |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
my %common = ( |
103
|
|
|
|
|
|
|
hri_style => $args->{hri_style}, |
104
|
|
|
|
|
|
|
prune_null_branches => $args->{prune_null_branches}, |
105
|
|
|
|
|
|
|
val_index => { map |
106
|
2215
|
|
|
|
|
5690
|
{ $args->{inflate_map}[$_] => $_ } |
107
|
234
|
|
|
|
|
1273
|
( 0 .. $#{$args->{inflate_map}} ) |
|
234
|
|
|
|
|
847
|
|
108
|
|
|
|
|
|
|
}, |
109
|
|
|
|
|
|
|
); |
110
|
|
|
|
|
|
|
|
111
|
234
|
|
|
|
|
840
|
my $check_null_columns; |
112
|
|
|
|
|
|
|
|
113
|
234
|
100
|
|
|
|
1113
|
my $src = (! $args->{collapse} ) ? assemble_simple_parser(\%common) : do { |
114
|
|
|
|
|
|
|
my $collapse_map = $self->_resolve_collapse ({ |
115
|
|
|
|
|
|
|
# FIXME |
116
|
|
|
|
|
|
|
# only consider real columns (not functions) during collapse resolution |
117
|
|
|
|
|
|
|
# this check shouldn't really be here, as fucktards are not supposed to |
118
|
|
|
|
|
|
|
# alias random crap to existing column names anyway, but still - just in |
119
|
|
|
|
|
|
|
# case |
120
|
|
|
|
|
|
|
# FIXME !!!! - this does not yet deal with unbalanced selectors correctly |
121
|
|
|
|
|
|
|
# (it is now trivial as the attrs specify where things go out of sync |
122
|
|
|
|
|
|
|
# needs MOAR tests) |
123
|
|
|
|
|
|
|
as => { map |
124
|
1653
|
100
|
|
|
|
5415
|
{ ref $attrs->{select}[$common{val_index}{$_}] ? () : ( $_ => $common{val_index}{$_} ) } |
125
|
166
|
|
|
|
|
799
|
keys %{$common{val_index}} |
126
|
|
|
|
|
|
|
}, |
127
|
|
|
|
|
|
|
premultiplied => $args->{premultiplied}, |
128
|
166
|
|
|
|
|
462
|
}); |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
$check_null_columns = $collapse_map->{-identifying_columns} |
131
|
166
|
100
|
|
|
|
836
|
if @{$collapse_map->{-identifying_columns}}; |
|
166
|
|
|
|
|
901
|
|
132
|
|
|
|
|
|
|
|
133
|
166
|
|
|
|
|
1464
|
assemble_collapsing_parser({ |
134
|
|
|
|
|
|
|
%common, |
135
|
|
|
|
|
|
|
collapse_map => $collapse_map, |
136
|
|
|
|
|
|
|
}); |
137
|
|
|
|
|
|
|
}; |
138
|
|
|
|
|
|
|
|
139
|
234
|
|
|
|
|
934
|
utf8::upgrade($src) |
140
|
|
|
|
|
|
|
if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE; |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
return ( |
143
|
234
|
100
|
50
|
41
|
|
24640
|
$args->{eval} ? ( eval "sub $src" || die $@ ) : $src, |
|
41
|
|
|
41
|
|
411
|
|
|
41
|
|
|
41
|
|
105
|
|
|
41
|
|
|
31
|
|
1455
|
|
|
41
|
|
|
31
|
|
331
|
|
|
41
|
|
|
31
|
|
147
|
|
|
41
|
|
|
1
|
|
2170
|
|
|
41
|
|
|
1
|
|
415
|
|
|
41
|
|
|
1
|
|
121
|
|
|
41
|
|
|
1
|
|
14831
|
|
|
31
|
|
|
1
|
|
355
|
|
|
31
|
|
|
1
|
|
100
|
|
|
31
|
|
|
1
|
|
1035
|
|
|
31
|
|
|
1
|
|
227
|
|
|
31
|
|
|
1
|
|
82
|
|
|
31
|
|
|
1
|
|
1375
|
|
|
31
|
|
|
1
|
|
397
|
|
|
31
|
|
|
1
|
|
85
|
|
|
31
|
|
|
1
|
|
9421
|
|
|
1
|
|
|
1
|
|
26
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
36
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
265
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
35
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
235
|
|
|
1
|
|
|
1
|
|
9
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
26
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
36
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
239
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
24
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
35
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
266
|
|
|
1
|
|
|
1
|
|
9
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
33
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
115
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
34
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
180
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
35
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
1
|
|
|
1
|
|
|
1
|
|
148
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
23
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
35
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
178
|
|
|
1
|
|
|
1
|
|
9
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
28
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
37
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
316
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
26
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
1
|
|
|
1
|
|
|
1
|
|
37
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
310
|
|
|
1
|
|
|
1
|
|
10
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
38
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
275
|
|
|
1
|
|
|
1
|
|
9
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
34
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
120
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
26
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
438
|
|
|
1
|
|
|
1
|
|
49
|
|
|
1
|
|
|
1
|
|
6
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
271
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
3
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
4
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
35
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
270
|
|
|
1
|
|
|
1
|
|
8
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
6
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
36
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
1
|
|
|
1
|
|
|
1
|
|
148
|
|
|
1
|
|
|
1
|
|
10
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
1
|
|
25
|
|
|
1
|
|
|
1
|
|
5
|
|
|
1
|
|
|
1
|
|
2
|
|
|
1
|
|
|
|
|
37
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
278
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
37
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
185
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
26
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
231
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
24
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
33
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
230
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
35
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
270
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
35
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
149
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
27
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
35
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
196
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
57
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
35
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
119
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
26
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
145
|
|
|
1
|
|
|
|
|
9
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
26
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
36
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
327
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
24
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
208
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
23
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
32
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
112
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
23
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
32
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
222
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
26
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
32
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
115
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
34
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
245
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
110
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
35
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
226
|
|
|
1
|
|
|
|
|
9
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
33
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
172
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
21
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
26
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
226
|
|
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
29
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
41
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
144
|
|
|
1
|
|
|
|
|
12
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
31
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
40
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
327
|
|
144
|
|
|
|
|
|
|
$check_null_columns, |
145
|
|
|
|
|
|
|
); |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# Takes an arrayref selection list and generates a collapse-map representing |
150
|
|
|
|
|
|
|
# row-object fold-points. Every relationship is assigned a set of unique, |
151
|
|
|
|
|
|
|
# non-nullable columns (which may *not even be* from the same resultset) |
152
|
|
|
|
|
|
|
# and the collapser will use this information to correctly distinguish |
153
|
|
|
|
|
|
|
# data of individual to-be-row-objects. See t/resultset/rowparser_internals.t |
154
|
|
|
|
|
|
|
# for extensive RV examples |
155
|
|
|
|
|
|
|
sub _resolve_collapse { |
156
|
561
|
|
|
561
|
|
1724
|
my ($self, $args, $common_args) = @_; |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# for comprehensible error messages put ourselves at the head of the relationship chain |
159
|
561
|
|
100
|
|
|
2657
|
$args->{_rel_chain} ||= [ $self->source_name ]; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# record top-level fully-qualified column index, signify toplevelness |
162
|
561
|
100
|
|
|
|
1863
|
unless ($common_args->{_as_fq_idx}) { |
163
|
169
|
|
|
|
|
384
|
$common_args->{_as_fq_idx} = { %{$args->{as}} }; |
|
169
|
|
|
|
|
1230
|
|
164
|
169
|
|
|
|
|
688
|
$args->{_is_top_level} = 1; |
165
|
|
|
|
|
|
|
}; |
166
|
|
|
|
|
|
|
|
167
|
561
|
|
|
|
|
1090
|
my ($my_cols, $rel_cols); |
168
|
561
|
|
|
|
|
927
|
for (keys %{$args->{as}}) { |
|
561
|
|
|
|
|
2266
|
|
169
|
3675
|
100
|
|
|
|
10196
|
if ($_ =~ /^ ([^\.]+) \. (.+) /x) { |
170
|
1953
|
|
|
|
|
5886
|
$rel_cols->{$1}{$2} = 1; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
else { |
173
|
1723
|
|
|
|
|
3918
|
$my_cols->{$_} = {}; # important for ||='s below |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
|
177
|
561
|
|
|
|
|
1278
|
my $relinfo; |
178
|
|
|
|
|
|
|
# run through relationships, collect metadata |
179
|
561
|
|
|
|
|
1664
|
for my $rel (keys %$rel_cols) { |
180
|
379
|
|
|
|
|
1703
|
my $inf = $self->relationship_info ($rel); |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
$relinfo->{$rel} = { |
183
|
|
|
|
|
|
|
is_single => ( $inf->{attrs}{accessor} && $inf->{attrs}{accessor} ne 'multi' ), |
184
|
379
|
|
66
|
|
|
3883
|
is_inner => ( ( $inf->{attrs}{join_type} || '' ) !~ /^left/i), |
|
|
|
100
|
|
|
|
|
185
|
|
|
|
|
|
|
rsrc => $self->related_source($rel), |
186
|
|
|
|
|
|
|
}; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# FIME - need to use _resolve_cond here instead |
189
|
379
|
|
|
|
|
1925
|
my $cond = $inf->{cond}; |
190
|
|
|
|
|
|
|
|
191
|
379
|
50
|
66
|
|
|
4003
|
if ( |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
192
|
|
|
|
|
|
|
ref $cond eq 'HASH' |
193
|
|
|
|
|
|
|
and |
194
|
|
|
|
|
|
|
keys %$cond |
195
|
|
|
|
|
|
|
and |
196
|
378
|
|
|
378
|
|
3327
|
! defined first { $_ !~ /^foreign\./ } (keys %$cond) |
197
|
|
|
|
|
|
|
and |
198
|
378
|
|
|
378
|
|
1830
|
! defined first { $_ !~ /^self\./ } (values %$cond) |
199
|
|
|
|
|
|
|
) { |
200
|
378
|
|
|
|
|
1135
|
for my $f (keys %$cond) { |
201
|
378
|
|
|
|
|
948
|
my $s = $cond->{$f}; |
202
|
378
|
|
|
|
|
2947
|
$_ =~ s/^ (?: foreign | self ) \.//x for ($f, $s); |
203
|
378
|
|
|
|
|
2547
|
$relinfo->{$rel}{fk_map}{$s} = $f; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# inject non-left fk-bridges from *INNER-JOINED* children (if any) |
209
|
561
|
|
|
|
|
1867
|
for my $rel (grep { $relinfo->{$_}{is_inner} } keys %$relinfo) { |
|
379
|
|
|
|
|
1269
|
|
210
|
124
|
|
|
|
|
316
|
my $ri = $relinfo->{$rel}; |
211
|
124
|
|
|
|
|
236
|
for (keys %{$ri->{fk_map}} ) { |
|
124
|
|
|
|
|
407
|
|
212
|
|
|
|
|
|
|
# need to know source from *our* pov, hence $rel.col |
213
|
|
|
|
|
|
|
$my_cols->{$_} ||= { via_fk => "$rel.$ri->{fk_map}{$_}" } |
214
|
124
|
100
|
100
|
|
|
789
|
if defined $rel_cols->{$rel}{$ri->{fk_map}{$_}} # in fact selected |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# if the parent is already defined *AND* we have an inner reverse relationship |
219
|
|
|
|
|
|
|
# (i.e. do not exist without it) , assume all of its related FKs are selected |
220
|
|
|
|
|
|
|
# (even if they in fact are NOT in the select list). Keep a record of what we |
221
|
|
|
|
|
|
|
# assumed, and if any such phantom-column becomes part of our own collapser, |
222
|
|
|
|
|
|
|
# throw everything assumed-from-parent away and replace with the collapser of |
223
|
|
|
|
|
|
|
# the parent (whatever it may be) |
224
|
561
|
|
|
|
|
1088
|
my $assumed_from_parent; |
225
|
561
|
100
|
100
|
|
|
2710
|
if ( ! $args->{_parent_info}{underdefined} and ! $args->{_parent_info}{rev_rel_is_optional} ) { |
226
|
395
|
100
|
|
|
|
878
|
for my $col ( values %{$args->{_parent_info}{rel_condition} || {}} ) { |
|
395
|
|
|
|
|
1754
|
|
227
|
227
|
100
|
|
|
|
762
|
next if exists $my_cols->{$col}; |
228
|
54
|
|
|
|
|
201
|
$my_cols->{$col} = { via_collapse => $args->{_parent_info}{collapse_on_idcols} }; |
229
|
54
|
|
|
|
|
210
|
$assumed_from_parent->{columns}{$col}++; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# get colinfo for everything |
234
|
561
|
100
|
|
|
|
1611
|
if ($my_cols) { |
235
|
541
|
|
|
|
|
2011
|
my $ci = $self->columns_info; |
236
|
541
|
|
|
|
|
3702
|
$my_cols->{$_}{colinfo} = $ci->{$_} for keys %$my_cols; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
561
|
|
|
|
|
1156
|
my $collapse_map; |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# first try to reuse the parent's collapser (i.e. reuse collapser over 1:1) |
242
|
|
|
|
|
|
|
# (makes for a leaner coderef later) |
243
|
561
|
50
|
|
|
|
1768
|
unless ($collapse_map->{-identifying_columns}) { |
244
|
|
|
|
|
|
|
$collapse_map->{-identifying_columns} = $args->{_parent_info}{collapse_on_idcols} |
245
|
561
|
100
|
|
|
|
1628
|
if $args->{_parent_info}{collapser_reusable}; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# Still don't know how to collapse - try to resolve based on our columns (plus already inserted FK bridges) |
249
|
561
|
100
|
100
|
|
|
3019
|
if ( |
|
|
|
100
|
|
|
|
|
250
|
|
|
|
|
|
|
! $collapse_map->{-identifying_columns} |
251
|
|
|
|
|
|
|
and |
252
|
|
|
|
|
|
|
$my_cols |
253
|
|
|
|
|
|
|
and |
254
|
1541
|
|
|
|
|
4963
|
my $idset = $self->_identifying_column_set ({map { $_ => $my_cols->{$_}{colinfo} } keys %$my_cols}) |
255
|
|
|
|
|
|
|
) { |
256
|
|
|
|
|
|
|
# see if the resulting collapser relies on any implied columns, |
257
|
|
|
|
|
|
|
# and fix stuff up if this is the case |
258
|
423
|
|
|
|
|
1032
|
my @reduced_set = grep { ! $assumed_from_parent->{columns}{$_} } @$idset; |
|
526
|
|
|
|
|
2142
|
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
$collapse_map->{-identifying_columns} = [ __unique_numlist( |
261
|
423
|
100
|
|
|
|
1840
|
@{ $args->{_parent_info}{collapse_on_idcols}||[] }, |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
(map |
264
|
|
|
|
|
|
|
{ |
265
|
423
|
|
|
|
|
860
|
my $fqc = join ('.', |
266
|
496
|
|
|
|
|
2904
|
@{$args->{_rel_chain}}[1 .. $#{$args->{_rel_chain}}], |
|
496
|
|
|
|
|
1143
|
|
267
|
496
|
|
66
|
|
|
1023
|
( $my_cols->{$_}{via_fk} || $_ ), |
268
|
|
|
|
|
|
|
); |
269
|
|
|
|
|
|
|
|
270
|
496
|
|
|
|
|
2063
|
$common_args->{_as_fq_idx}->{$fqc}; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
@reduced_set |
273
|
|
|
|
|
|
|
), |
274
|
|
|
|
|
|
|
)]; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# Stil don't know how to collapse - keep descending down 1:1 chains - if |
278
|
|
|
|
|
|
|
# a related non-LEFT 1:1 is resolvable - its condition will collapse us |
279
|
|
|
|
|
|
|
# too |
280
|
561
|
100
|
|
|
|
2585
|
unless ($collapse_map->{-identifying_columns}) { |
281
|
42
|
|
|
|
|
96
|
my @candidates; |
282
|
|
|
|
|
|
|
|
283
|
42
|
|
|
|
|
120
|
for my $rel (keys %$relinfo) { |
284
|
53
|
100
|
100
|
|
|
300
|
next unless ($relinfo->{$rel}{is_single} && $relinfo->{$rel}{is_inner}); |
285
|
|
|
|
|
|
|
|
286
|
28
|
50
|
|
|
|
74
|
if ( my $rel_collapse = $relinfo->{$rel}{rsrc}->_resolve_collapse ({ |
287
|
|
|
|
|
|
|
as => $rel_cols->{$rel}, |
288
|
28
|
|
|
|
|
258
|
_rel_chain => [ @{$args->{_rel_chain}}, $rel ], |
289
|
|
|
|
|
|
|
_parent_info => { underdefined => 1 }, |
290
|
|
|
|
|
|
|
}, $common_args)) { |
291
|
28
|
|
|
|
|
307
|
push @candidates, $rel_collapse->{-identifying_columns}; |
292
|
|
|
|
|
|
|
} |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# get the set with least amount of columns |
296
|
|
|
|
|
|
|
# FIXME - maybe need to implement a data type order as well (i.e. prefer several ints |
297
|
|
|
|
|
|
|
# to a single varchar) |
298
|
42
|
100
|
|
|
|
142
|
if (@candidates) { |
299
|
28
|
|
|
|
|
83
|
($collapse_map->{-identifying_columns}) = sort { scalar @$a <=> scalar @$b } (@candidates); |
|
1
|
|
|
|
|
25
|
|
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# Stil don't know how to collapse, and we are the root node. Last ditch |
304
|
|
|
|
|
|
|
# effort in case we are *NOT* premultiplied. |
305
|
|
|
|
|
|
|
# Run through *each multi* all the way down, left or not, and all |
306
|
|
|
|
|
|
|
# *left* singles (a single may become a multi underneath) . When everything |
307
|
|
|
|
|
|
|
# gets back see if all the rels link to us definitively. If this is the |
308
|
|
|
|
|
|
|
# case we are good - either one of them will define us, or if all are NULLs |
309
|
|
|
|
|
|
|
# we know we are "unique" due to the "non-premultiplied" check |
310
|
561
|
50
|
66
|
|
|
2066
|
if ( |
|
|
|
66
|
|
|
|
|
311
|
|
|
|
|
|
|
! $collapse_map->{-identifying_columns} |
312
|
|
|
|
|
|
|
and |
313
|
|
|
|
|
|
|
! $args->{premultiplied} |
314
|
|
|
|
|
|
|
and |
315
|
|
|
|
|
|
|
$args->{_is_top_level} |
316
|
|
|
|
|
|
|
) { |
317
|
15
|
|
|
|
|
40
|
my (@collapse_sets, $uncollapsible_chain); |
318
|
|
|
|
|
|
|
|
319
|
15
|
|
|
|
|
78
|
for my $rel (keys %$relinfo) { |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# we already looked at these higher up |
322
|
23
|
50
|
66
|
|
|
93
|
next if ($relinfo->{$rel}{is_single} && $relinfo->{$rel}{is_inner}); |
323
|
|
|
|
|
|
|
|
324
|
23
|
50
|
|
|
|
62
|
if (my $clps = $relinfo->{$rel}{rsrc}->_resolve_collapse ({ |
325
|
|
|
|
|
|
|
as => $rel_cols->{$rel}, |
326
|
23
|
|
|
|
|
433
|
_rel_chain => [ @{$args->{_rel_chain}}, $rel ], |
327
|
|
|
|
|
|
|
_parent_info => { underdefined => 1 }, |
328
|
|
|
|
|
|
|
}, $common_args) ) { |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# for singles use the idcols wholesale (either there or not) |
331
|
23
|
100
|
|
|
|
99
|
if ($relinfo->{$rel}{is_single}) { |
|
|
50
|
|
|
|
|
|
332
|
9
|
|
|
|
|
51
|
push @collapse_sets, $clps->{-identifying_columns}; |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
elsif (! $relinfo->{$rel}{fk_map}) { |
335
|
1
|
|
|
|
|
28
|
$uncollapsible_chain = 1; |
336
|
1
|
|
|
|
|
5
|
last; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
else { |
339
|
15
|
|
|
|
|
32
|
my $defined_cols_parent_side; |
340
|
|
|
|
|
|
|
|
341
|
15
|
|
|
|
|
65
|
for my $fq_col ( grep { /^$rel\.[^\.]+$/ } keys %{$args->{as}} ) { |
|
96
|
|
|
|
|
585
|
|
|
15
|
|
|
|
|
59
|
|
342
|
39
|
|
|
|
|
494
|
my ($col) = $fq_col =~ /([^\.]+)$/; |
343
|
|
|
|
|
|
|
|
344
|
39
|
|
|
|
|
81
|
$defined_cols_parent_side->{$_} = $args->{as}{$fq_col} for grep |
345
|
39
|
|
|
|
|
176
|
{ $relinfo->{$rel}{fk_map}{$_} eq $col } |
346
|
39
|
|
|
|
|
127
|
keys %{$relinfo->{$rel}{fk_map}} |
347
|
|
|
|
|
|
|
; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
15
|
50
|
|
|
|
106
|
if (my $set = $self->_identifying_column_set([ keys %$defined_cols_parent_side ]) ) { |
351
|
15
|
|
|
|
|
63
|
push @collapse_sets, [ sort map { $defined_cols_parent_side->{$_} } @$set ]; |
|
15
|
|
|
|
|
168
|
|
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
else { |
354
|
1
|
|
|
|
|
5
|
$uncollapsible_chain = 1; |
355
|
1
|
|
|
|
|
3
|
last; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
else { |
360
|
1
|
|
|
|
|
368
|
$uncollapsible_chain = 1; |
361
|
1
|
|
|
|
|
8
|
last; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
15
|
50
|
|
|
|
58
|
unless ($uncollapsible_chain) { |
366
|
|
|
|
|
|
|
# if we got here - we are good to go, but the construction is tricky |
367
|
|
|
|
|
|
|
# since our children will want to include our collapse criteria - we |
368
|
|
|
|
|
|
|
# don't give them anything (safe, since they are all collapsible on their own) |
369
|
|
|
|
|
|
|
# in addition we record the individual collapse possibilities |
370
|
|
|
|
|
|
|
# of all left children node collapsers, and merge them in the rowparser |
371
|
|
|
|
|
|
|
# coderef later |
372
|
15
|
|
|
|
|
64
|
$collapse_map->{-identifying_columns} = []; |
373
|
|
|
|
|
|
|
$collapse_map->{-identifying_columns_variants} = [ sort { |
374
|
15
|
0
|
|
|
|
53
|
(scalar @$a) <=> (scalar @$b) or max(@$a) <=> max(@$b) |
|
9
|
|
|
|
|
89
|
|
375
|
|
|
|
|
|
|
} @collapse_sets ]; |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# stop descending into children if we were called by a parent for first-pass |
380
|
|
|
|
|
|
|
# and don't despair if nothing was found (there may be other parallel branches |
381
|
|
|
|
|
|
|
# to dive into) |
382
|
561
|
100
|
|
|
|
1993
|
if ($args->{_parent_info}{underdefined}) { |
|
|
50
|
|
|
|
|
|
383
|
50
|
50
|
|
|
|
372
|
return $collapse_map->{-identifying_columns} ? $collapse_map : undef |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
# nothing down the chain resolved - can't calculate a collapse-map |
386
|
|
|
|
|
|
|
elsif (! $collapse_map->{-identifying_columns}) { |
387
|
|
|
|
|
|
|
$self->throw_exception ( sprintf |
388
|
|
|
|
|
|
|
"Unable to calculate a definitive collapse column set for %s%s: fetch more unique non-nullable columns", |
389
|
|
|
|
|
|
|
$self->source_name, |
390
|
1
|
|
|
|
|
178
|
@{$args->{_rel_chain}} > 1 |
391
|
1
|
0
|
|
|
|
2
|
? sprintf (' (last member of the %s chain)', join ' -> ', @{$args->{_rel_chain}} ) |
|
1
|
|
|
|
|
7
|
|
392
|
|
|
|
|
|
|
: '' |
393
|
|
|
|
|
|
|
, |
394
|
|
|
|
|
|
|
); |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# If we got that far - we are collapsable - GREAT! Now go down all children |
398
|
|
|
|
|
|
|
# a second time, and fill in the rest |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
$collapse_map->{-identifying_columns} = [ __unique_numlist( |
401
|
512
|
100
|
|
|
|
1775
|
@{ $args->{_parent_info}{collapse_on_idcols}||[] }, |
402
|
512
|
|
|
|
|
895
|
@{ $collapse_map->{-identifying_columns} }, |
|
512
|
|
|
|
|
1442
|
|
403
|
|
|
|
|
|
|
)]; |
404
|
|
|
|
|
|
|
|
405
|
512
|
|
|
|
|
1285
|
my @id_sets; |
406
|
512
|
|
|
|
|
1605
|
for my $rel (sort keys %$relinfo) { |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
$collapse_map->{$rel} = $relinfo->{$rel}{rsrc}->_resolve_collapse ({ |
409
|
1820
|
|
|
|
|
3603
|
as => { map { $_ => 1 } ( keys %{$rel_cols->{$rel}} ) }, |
|
344
|
|
|
|
|
1426
|
|
410
|
344
|
|
|
|
|
1104
|
_rel_chain => [ @{$args->{_rel_chain}}, $rel], |
411
|
|
|
|
|
|
|
_parent_info => { |
412
|
|
|
|
|
|
|
# shallow copy |
413
|
344
|
|
|
|
|
1801
|
collapse_on_idcols => [ @{$collapse_map->{-identifying_columns}} ], |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
rel_condition => $relinfo->{$rel}{fk_map}, |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
is_optional => ! $relinfo->{$rel}{is_inner}, |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
# if there is at least one *inner* reverse relationship which is HASH-based (equality only) |
420
|
|
|
|
|
|
|
# we can safely assume that the child can not exist without us |
421
|
|
|
|
|
|
|
rev_rel_is_optional => ( first |
422
|
430
|
50
|
100
|
430
|
|
7455
|
{ ref $_->{cond} eq 'HASH' and ($_->{attrs}{join_type}||'') !~ /^left/i } |
423
|
344
|
|
|
|
|
1930
|
values %{ $self->reverse_relationship_info($rel) }, |
424
|
|
|
|
|
|
|
) ? 0 : 1, |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# if this is a 1:1 our own collapser can be used as a collapse-map |
427
|
|
|
|
|
|
|
# (regardless of left or not) |
428
|
|
|
|
|
|
|
collapser_reusable => ( |
429
|
|
|
|
|
|
|
$relinfo->{$rel}{is_single} |
430
|
|
|
|
|
|
|
&& |
431
|
|
|
|
|
|
|
$relinfo->{$rel}{is_inner} |
432
|
|
|
|
|
|
|
&& |
433
|
344
|
100
|
66
|
|
|
890
|
@{$collapse_map->{-identifying_columns}} |
|
|
100
|
|
|
|
|
|
434
|
|
|
|
|
|
|
) ? 1 : 0, |
435
|
|
|
|
|
|
|
}, |
436
|
|
|
|
|
|
|
}, $common_args ); |
437
|
|
|
|
|
|
|
|
438
|
344
|
100
|
|
|
|
2704
|
$collapse_map->{$rel}{-is_single} = 1 if $relinfo->{$rel}{is_single}; |
439
|
344
|
100
|
50
|
|
|
1674
|
$collapse_map->{$rel}{-is_optional} ||= 1 unless $relinfo->{$rel}{is_inner}; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
512
|
|
|
|
|
3246
|
return $collapse_map; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
# adding a dep on MoreUtils *just* for this is retarded |
446
|
|
|
|
|
|
|
sub __unique_numlist { |
447
|
934
|
|
|
934
|
|
1444
|
sort { $a <=> $b } keys %{ {map { $_ => 1 } @_ }} |
|
1132
|
|
|
|
|
4133
|
|
|
934
|
|
|
|
|
1707
|
|
|
2283
|
|
|
|
|
8048
|
|
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
1; |