line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package UR::DataSource; |
2
|
217
|
|
|
217
|
|
6174
|
use strict; |
|
217
|
|
|
|
|
297
|
|
|
217
|
|
|
|
|
5973
|
|
3
|
217
|
|
|
217
|
|
727
|
use warnings; |
|
217
|
|
|
|
|
306
|
|
|
217
|
|
|
|
|
9373
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
require UR; |
6
|
|
|
|
|
|
|
our $VERSION = "0.46"; # UR $VERSION; |
7
|
217
|
|
|
217
|
|
823
|
use Sys::Hostname; |
|
217
|
|
|
|
|
271
|
|
|
217
|
|
|
|
|
11873
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
{ |
10
|
217
|
|
|
217
|
|
763
|
no warnings 'once'; |
|
217
|
|
|
|
|
270
|
|
|
217
|
|
|
|
|
47516
|
|
11
|
|
|
|
|
|
|
*namespace = \&get_namespace; |
12
|
|
|
|
|
|
|
} |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
UR::Object::Type->define( |
15
|
|
|
|
|
|
|
class_name => 'UR::DataSource', |
16
|
|
|
|
|
|
|
is_abstract => 1, |
17
|
|
|
|
|
|
|
doc => 'A logical database, independent of prod/dev/testing considerations or login details.', |
18
|
|
|
|
|
|
|
has => [ |
19
|
|
|
|
|
|
|
namespace => { calculate_from => ['id'] }, |
20
|
|
|
|
|
|
|
is_connected => { is => 'Boolean', default_value => 0, is_optional => 1, is_transient => 1 }, |
21
|
|
|
|
|
|
|
get_default_handle => { |
22
|
|
|
|
|
|
|
is_calculated => 1, |
23
|
|
|
|
|
|
|
is_constant => 1, |
24
|
|
|
|
|
|
|
doc => 'Underlying handle for this datasource', |
25
|
|
|
|
|
|
|
calculate => '$self->create_default_handle_wrapper', |
26
|
|
|
|
|
|
|
}, |
27
|
|
|
|
|
|
|
], |
28
|
|
|
|
|
|
|
valid_signals => ['precreate_handle', 'create_handle', 'predisconnect_handle', 'disconnect_handle' ], |
29
|
|
|
|
|
|
|
); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
our @CARP_NOT = qw(UR::Context UR::DataSource::QueryPlan); |
32
|
|
|
|
|
|
|
|
33
|
12
|
|
|
12
|
0
|
56
|
sub define { shift->__define__(@_) } |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub get_namespace { |
36
|
1667
|
|
|
1667
|
0
|
4611
|
my $class = shift->class; |
37
|
1667
|
|
|
|
|
5345
|
return substr($class,0,index($class,"::DataSource")); |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub get_name { |
41
|
0
|
|
|
0
|
0
|
0
|
my $class = shift->class; |
42
|
0
|
|
|
|
|
0
|
return lc(substr($class,index($class,"::DataSource")+14)); |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# The default used to be to force table/column/constraint/etc names to |
46
|
|
|
|
|
|
|
# upper case when storing them in the MetaDB, and in the column_name |
47
|
|
|
|
|
|
|
# metadata for properties. The new behavior is to just use whatever the |
48
|
|
|
|
|
|
|
# database supplies us when interrogating the data dictionary. |
49
|
|
|
|
|
|
|
# For datasources/clases that still need the old behavior, override this |
50
|
|
|
|
|
|
|
# to make the column_name metadata for properties forced to upper-case |
51
|
3012
|
|
|
3012
|
0
|
6964
|
sub table_and_column_names_are_upper_case { 0; } |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Basic, dumb data sources do not support joins within a single |
55
|
|
|
|
|
|
|
# query. Instead the Context logic can perform a cross datasource |
56
|
|
|
|
|
|
|
# join within irs own code |
57
|
3
|
|
|
3
|
0
|
19
|
sub does_support_joins { 0; } |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Many data sources do not support limit and offset. |
60
|
|
|
|
|
|
|
sub does_support_limit_offset { |
61
|
|
|
|
|
|
|
#my($self, $query_plan) = @_; |
62
|
0
|
|
|
0
|
0
|
0
|
0 |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Most datasources do not support recursive queries |
66
|
|
|
|
|
|
|
# Oracle and Postgres do, but in different ways |
67
|
|
|
|
|
|
|
# For data sources without support, it'll have to do multiple queries |
68
|
|
|
|
|
|
|
# to get all the data |
69
|
10
|
|
|
10
|
0
|
31
|
sub does_support_recursive_queries { ''; } |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
{ |
73
|
217
|
|
|
217
|
|
893
|
no warnings 'once'; |
|
217
|
|
|
|
|
272
|
|
|
217
|
|
|
|
|
194009
|
|
74
|
|
|
|
|
|
|
*create_dbh = \&create_default_handle_wrapper; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub create_default_handle_wrapper { |
78
|
549
|
|
|
549
|
0
|
2036
|
my $self = UR::Util::object(shift); |
79
|
|
|
|
|
|
|
|
80
|
549
|
|
|
|
|
2837
|
$self->__signal_observers__('precreate_handle'); |
81
|
549
|
|
|
|
|
2673
|
my $h = $self->create_default_handle; |
82
|
547
|
|
|
|
|
1843
|
$self->__signal_observers__('create_handle', $h); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Hack - This is to avoid infinite recursion in the case where the |
85
|
|
|
|
|
|
|
# handle initializers below try to get the hadle by calling $ds->get_default_handle. |
86
|
|
|
|
|
|
|
# The cached/calculated accessor code will look in this hash key and |
87
|
|
|
|
|
|
|
# return the handle instead of recursing back into the handle creation, and |
88
|
|
|
|
|
|
|
# back to here |
89
|
547
|
|
|
|
|
1275
|
$self->{get_default_handle} = $h; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Backward compatability for older code that still uses _init_created_dbh |
92
|
547
|
100
|
|
|
|
2310
|
if ($self->can('_init_created_dbh')) { |
93
|
172
|
|
|
|
|
2342
|
$self->_init_created_dbh($h); |
94
|
|
|
|
|
|
|
} else { |
95
|
375
|
|
|
|
|
27088
|
$self->init_created_handle($h); |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
547
|
|
|
|
|
1863
|
return $h; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# basic, dumb datasources do not have a handle |
102
|
0
|
|
|
0
|
0
|
0
|
sub create_default_handle { undef } |
103
|
|
|
|
0
|
0
|
|
sub disconnect { } |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# derived classes can implement this to do extra initialization after the |
106
|
|
|
|
|
|
|
# handle is created |
107
|
375
|
|
|
375
|
0
|
435
|
sub init_created_handle { 1; } |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Peek into the object and see if there's anything in 'get_default_handle' without actually |
110
|
|
|
|
|
|
|
# creating a handle |
111
|
|
|
|
|
|
|
*has_default_dbh = \&has_default_handle; |
112
|
|
|
|
|
|
|
sub has_default_handle { |
113
|
649
|
|
|
649
|
0
|
1451
|
my $self = UR::Util::object(shift); |
114
|
649
|
|
|
|
|
2294
|
return exists($self->{get_default_handle}); |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
*disconnect_default_dbh = \&disconnect_default_handle; |
118
|
|
|
|
|
|
|
sub disconnect_default_handle { |
119
|
13
|
|
|
13
|
0
|
857
|
my $self = shift; |
120
|
|
|
|
|
|
|
|
121
|
13
|
100
|
|
|
|
57
|
if ($self->has_default_handle) { |
122
|
3
|
|
|
|
|
14
|
$self->__signal_observers__('predisconnect_handle'); |
123
|
3
|
|
|
|
|
19
|
$self->disconnect(); |
124
|
3
|
|
|
|
|
43
|
$self->__signal_observers__('disconnect_handle'); |
125
|
|
|
|
|
|
|
} |
126
|
13
|
|
|
|
|
31
|
1; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
our $use_dummy_autogenerated_ids; |
130
|
|
|
|
|
|
|
*use_dummy_autogenerated_ids = \$ENV{UR_USE_DUMMY_AUTOGENERATED_IDS}; |
131
|
|
|
|
|
|
|
sub use_dummy_autogenerated_ids { |
132
|
|
|
|
|
|
|
# This allows the saved SQL from sync database to be comparable across executions. |
133
|
|
|
|
|
|
|
# It also |
134
|
162
|
|
|
162
|
1
|
246
|
my $class = shift; |
135
|
162
|
50
|
|
|
|
486
|
if (@_) { |
136
|
0
|
|
|
|
|
0
|
($use_dummy_autogenerated_ids) = @_; |
137
|
|
|
|
|
|
|
} |
138
|
162
|
|
50
|
|
|
1607
|
$use_dummy_autogenerated_ids ||= 0; # Replace undef with 0 |
139
|
162
|
|
|
|
|
508
|
return $use_dummy_autogenerated_ids; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
our $last_dummy_autogenerated_id; |
143
|
|
|
|
|
|
|
sub next_dummy_autogenerated_id { |
144
|
0
|
0
|
|
0
|
1
|
0
|
unless($last_dummy_autogenerated_id) { |
145
|
0
|
|
|
|
|
0
|
my $hostname = hostname(); |
146
|
0
|
|
|
|
|
0
|
$hostname =~ /(\d+)/; |
147
|
0
|
0
|
|
|
|
0
|
my $id = $1 ? $1 : 1; |
148
|
0
|
|
|
|
|
0
|
$last_dummy_autogenerated_id = ($id * -10_000_000) - ($$ * 1_000); |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
#limit id to fit within 11 characters |
152
|
0
|
|
|
|
|
0
|
($last_dummy_autogenerated_id) = $last_dummy_autogenerated_id =~ m/(-\d{1,10})/; |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
0
|
return --$last_dummy_autogenerated_id; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub autogenerate_new_object_id_for_class_name_and_rule { |
158
|
0
|
|
|
0
|
1
|
0
|
my $ds = shift; |
159
|
|
|
|
|
|
|
|
160
|
0
|
0
|
|
|
|
0
|
if (ref $ds) { |
161
|
0
|
|
|
|
|
0
|
$ds = ref($ds) . " ID " . $ds->id; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Maybe we could use next_dummy_autogenerated_id instead? |
165
|
0
|
|
|
|
|
0
|
die "Data source $ds did not implement autogenerate_new_object_id_for_class_name_and_rule()"; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# UR::Context needs to know if a data source supports savepoints |
169
|
|
|
|
|
|
|
sub can_savepoint { |
170
|
0
|
|
|
0
|
0
|
0
|
my $class = ref($_[0]); |
171
|
0
|
|
|
|
|
0
|
die "Class $class didn't supply can_savepoint()"; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub set_savepoint { |
175
|
0
|
|
|
0
|
0
|
0
|
my $class = ref($_[0]); |
176
|
0
|
|
|
|
|
0
|
die "Class $class didn't supply set_savepoint, but can_savepoint is true"; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub rollback_to_savepoint { |
180
|
0
|
|
|
0
|
0
|
0
|
my $class = ref($_[0]); |
181
|
0
|
|
|
|
|
0
|
die "Class $class didn't supply rollback_to_savepoint, but can_savepoint is true"; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub _get_class_data_for_loading { |
186
|
3897
|
|
|
3897
|
|
5875
|
my ($self, $class_meta) = @_; |
187
|
3897
|
|
|
|
|
6361
|
my $class_data = $class_meta->{loading_data_cache}; |
188
|
3897
|
50
|
|
|
|
8132
|
unless ($class_data) { |
189
|
3897
|
|
|
|
|
13346
|
$class_data = $self->_generate_class_data_for_loading($class_meta); |
190
|
|
|
|
|
|
|
} |
191
|
3897
|
|
|
|
|
10900
|
return $class_data; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub _resolve_query_plan { |
195
|
3838
|
|
|
3838
|
|
4605
|
my ($self, $rule_template) = @_; |
196
|
3838
|
|
|
|
|
14996
|
my $qp = UR::DataSource::QueryPlan->get( |
197
|
|
|
|
|
|
|
rule_template => $rule_template, |
198
|
|
|
|
|
|
|
data_source => $self, |
199
|
|
|
|
|
|
|
); |
200
|
3838
|
100
|
|
|
|
12602
|
$qp->_init() unless $qp->_is_initialized; |
201
|
3838
|
|
|
|
|
9845
|
return $qp; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# Child classes can override this to return a different datasource |
205
|
|
|
|
|
|
|
# depending on the rule passed in |
206
|
|
|
|
|
|
|
sub resolve_data_sources_for_rule { |
207
|
4488
|
|
|
4488
|
1
|
7352
|
return $_[0]; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub _generate_class_data_for_loading { |
211
|
3897
|
|
|
3897
|
|
4594
|
my ($self, $class_meta) = @_; |
212
|
|
|
|
|
|
|
|
213
|
3897
|
|
|
|
|
11375
|
my $class_name = $class_meta->class_name; |
214
|
3897
|
|
|
|
|
17464
|
my $ghost_class = $class_name->ghost_class; |
215
|
|
|
|
|
|
|
|
216
|
3897
|
|
|
|
|
15288
|
my @all_id_property_names = $class_meta->all_id_property_names(); |
217
|
3897
|
|
|
|
|
11702
|
my @id_properties = $class_meta->id_property_names; |
218
|
3897
|
|
|
|
|
13639
|
my $id_property_sorter = $class_meta->id_property_sorter; |
219
|
3897
|
|
|
|
|
9518
|
my @class_hierarchy = ($class_meta->class_name,$class_meta->ancestry_class_names); |
220
|
|
|
|
|
|
|
|
221
|
3897
|
|
|
|
|
12581
|
my @parent_class_objects = $class_meta->ancestry_class_metas; |
222
|
3897
|
|
|
|
|
5238
|
my $sub_classification_method_name; |
223
|
3897
|
|
|
|
|
4302
|
my ($sub_classification_meta_class_name, $subclassify_by); |
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
0
|
my @all_properties; |
226
|
0
|
|
|
|
|
0
|
my $first_table_name; |
227
|
0
|
|
|
|
|
0
|
my %seen; |
228
|
3897
|
|
|
|
|
6693
|
for my $co ( $class_meta, @parent_class_objects ) { |
229
|
12487
|
100
|
|
|
|
37098
|
next if ($seen{ $co->id })++; |
230
|
12485
|
|
100
|
|
|
32032
|
my $table_name = $co->table_name || '__default__'; |
231
|
|
|
|
|
|
|
|
232
|
12485
|
|
66
|
|
|
26392
|
$first_table_name ||= $table_name; |
233
|
12485
|
|
100
|
|
|
40477
|
$sub_classification_method_name ||= $co->sub_classification_method_name; |
234
|
12485
|
|
33
|
|
|
38758
|
$sub_classification_meta_class_name ||= $co->sub_classification_meta_class_name; |
235
|
12485
|
|
100
|
|
|
38638
|
$subclassify_by ||= $co->subclassify_by; |
236
|
|
|
|
|
|
|
|
237
|
12485
|
|
|
29515
|
|
42812
|
my $sort_sub = sub ($$) { return $_[0]->property_name cmp $_[1]->property_name }; |
|
29515
|
|
|
|
|
43495
|
|
238
|
12485
|
|
|
|
|
32681
|
push @all_properties, map { [$co, $_, $table_name, 0]} sort $sort_sub UR::Object::Property->get(class_name => $co->class_name); |
|
24210
|
|
|
|
|
68205
|
|
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
3897
|
|
|
|
|
12019
|
my $sub_typing_property = $class_meta->subclassify_by; |
242
|
|
|
|
|
|
|
|
243
|
3897
|
|
|
|
|
10322
|
my $class_table_name = $class_meta->table_name; |
244
|
|
|
|
|
|
|
|
245
|
3897
|
|
|
|
|
14950
|
my $class_data = { |
246
|
|
|
|
|
|
|
class_name => $class_name, |
247
|
|
|
|
|
|
|
ghost_class => $class_name->ghost_class, |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
parent_class_objects => [$class_meta->ancestry_class_metas], ## |
250
|
|
|
|
|
|
|
sub_classification_method_name => $sub_classification_method_name, |
251
|
|
|
|
|
|
|
sub_classification_meta_class_name => $sub_classification_meta_class_name, |
252
|
|
|
|
|
|
|
subclassify_by => $subclassify_by, |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
all_properties => \@all_properties, |
255
|
|
|
|
|
|
|
all_id_property_names => [$class_meta->all_id_property_names()], |
256
|
|
|
|
|
|
|
id_properties => [$class_meta->id_property_names], |
257
|
|
|
|
|
|
|
id_property_sorter => $class_meta->id_property_sorter, |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub_typing_property => $sub_typing_property, |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# these seem like they go in the RDBMS subclass, but for now the |
262
|
|
|
|
|
|
|
# "table" concept is stretched to mean any valid structure identifier |
263
|
|
|
|
|
|
|
# within the datasource. |
264
|
|
|
|
|
|
|
first_table_name => $first_table_name, |
265
|
|
|
|
|
|
|
class_table_name => $class_table_name, |
266
|
|
|
|
|
|
|
}; |
267
|
|
|
|
|
|
|
|
268
|
3897
|
|
|
|
|
20329
|
return $class_data; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub _generate_loading_templates_arrayref { |
272
|
|
|
|
|
|
|
# Each entry represents a table alias in the query. |
273
|
|
|
|
|
|
|
# This accounts for different tables, or multiple occurrances |
274
|
|
|
|
|
|
|
# of the same table in a join, by grouping by alias instead of |
275
|
|
|
|
|
|
|
# table. |
276
|
|
|
|
|
|
|
|
277
|
785
|
|
|
785
|
|
1249
|
my $class = shift; |
278
|
785
|
|
|
|
|
1080
|
my $db_cols = shift; |
279
|
785
|
|
|
|
|
1048
|
my $obj_joins = shift; |
280
|
785
|
|
|
|
|
1133
|
my $bxt = shift; |
281
|
|
|
|
|
|
|
|
282
|
217
|
|
|
217
|
|
1116
|
use strict; |
|
217
|
|
|
|
|
294
|
|
|
217
|
|
|
|
|
3966
|
|
283
|
217
|
|
|
217
|
|
714
|
use warnings; |
|
217
|
|
|
|
|
264
|
|
|
217
|
|
|
|
|
443360
|
|
284
|
|
|
|
|
|
|
|
285
|
785
|
|
|
|
|
1003
|
my %obj_joins_by_source_alias; |
286
|
785
|
|
|
|
|
1244
|
if (0) { # ($obj_joins) { |
287
|
|
|
|
|
|
|
my @obj_joins = @$obj_joins; |
288
|
|
|
|
|
|
|
while (@obj_joins) { |
289
|
|
|
|
|
|
|
my $foreign_alias = shift @obj_joins; |
290
|
|
|
|
|
|
|
my $data = shift @obj_joins; |
291
|
|
|
|
|
|
|
for my $foreign_property_name (sort keys %$data) { |
292
|
|
|
|
|
|
|
next if $foreign_property_name eq '-is_required'; |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
my $source_alias = $data->{$foreign_property_name}{'link_alias'}; |
295
|
|
|
|
|
|
|
my $detail = $obj_joins_by_source_alias{$source_alias}{$foreign_alias} ||= {}; |
296
|
|
|
|
|
|
|
# warnings come from the above because we don't have 'link_alias' in filters. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
my $source_property_name = $data->{$foreign_property_name}{'link_property_name'}; |
299
|
|
|
|
|
|
|
if ($source_property_name) { |
300
|
|
|
|
|
|
|
# join |
301
|
|
|
|
|
|
|
my $links = $detail->{links} ||= []; |
302
|
|
|
|
|
|
|
push @$links, $foreign_property_name, $source_property_name; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
if (exists $data->{value}) { |
306
|
|
|
|
|
|
|
# filter |
307
|
|
|
|
|
|
|
my $operator = $data->{operator}; |
308
|
|
|
|
|
|
|
my $value = $data->{value}; |
309
|
|
|
|
|
|
|
my $filter = $detail->{filter} ||= []; |
310
|
|
|
|
|
|
|
my $key = $foreign_property_name; |
311
|
|
|
|
|
|
|
$key .= ' ' . $operator if $operator; |
312
|
|
|
|
|
|
|
push @$filter, $key, $value; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
else { |
318
|
|
|
|
|
|
|
#Carp::cluck("no obj joins???"); |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
785
|
|
|
|
|
1108
|
my %templates; |
322
|
785
|
|
|
|
|
1131
|
my $pos = 0; |
323
|
785
|
|
|
|
|
1008
|
my @templates; |
324
|
|
|
|
|
|
|
my %alias_object_num; |
325
|
785
|
|
|
|
|
1566
|
for my $col_data (@$db_cols) { |
326
|
3599
|
|
|
|
|
3970
|
my ($class_obj, $prop, $table_alias, $object_num) = @$col_data; |
327
|
3599
|
50
|
|
|
|
5140
|
unless (defined $object_num) { |
328
|
0
|
|
|
|
|
0
|
die "No object num for loading template data?!"; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
#Carp::confess() unless $table_alias; |
331
|
3599
|
|
|
|
|
3309
|
my $template = $templates[$object_num]; |
332
|
3599
|
100
|
|
|
|
5180
|
unless ($template) { |
333
|
906
|
|
|
|
|
2875
|
$template = { |
334
|
|
|
|
|
|
|
object_num => $object_num, |
335
|
|
|
|
|
|
|
table_alias => $table_alias, |
336
|
|
|
|
|
|
|
data_class_name => $class_obj->class_name, |
337
|
|
|
|
|
|
|
final_class_name => $class_obj->class_name, |
338
|
|
|
|
|
|
|
property_names => [], |
339
|
|
|
|
|
|
|
column_positions => [], |
340
|
|
|
|
|
|
|
id_property_names => undef, |
341
|
|
|
|
|
|
|
id_column_positions => [], |
342
|
|
|
|
|
|
|
id_resolver => undef, # subref |
343
|
|
|
|
|
|
|
}; |
344
|
906
|
|
|
|
|
1991
|
$templates[$object_num] = $template; |
345
|
906
|
|
|
|
|
1859
|
$alias_object_num{$table_alias} = $object_num; |
346
|
|
|
|
|
|
|
} |
347
|
3599
|
|
|
|
|
2542
|
push @{ $template->{property_names} }, $prop->property_name; |
|
3599
|
|
|
|
|
6727
|
|
348
|
3599
|
|
|
|
|
3068
|
push @{ $template->{column_positions} }, $pos; |
|
3599
|
|
|
|
|
3666
|
|
349
|
3599
|
|
|
|
|
3951
|
$pos++; |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# remove joins that resulted in no template, such as when it was to a table-less class |
353
|
785
|
|
|
|
|
1435
|
@templates = grep { $_ } @templates; |
|
906
|
|
|
|
|
2025
|
|
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
# Post-process the template objects a bit to get the exact id positions. |
356
|
785
|
|
|
|
|
1470
|
for my $template (@templates) { |
357
|
906
|
|
|
|
|
1089
|
my @id_property_names; |
358
|
906
|
|
|
|
|
25629
|
for my $id_class_name ($template->{data_class_name}, $template->{data_class_name}->inheritance) { |
359
|
906
|
|
|
|
|
3565
|
my $id_class_obj = UR::Object::Type->get(class_name => $id_class_name); |
360
|
906
|
50
|
|
|
|
3469
|
last if @id_property_names = $id_class_obj->id_property_names; |
361
|
|
|
|
|
|
|
} |
362
|
906
|
|
|
|
|
2073
|
$template->{id_property_names} = \@id_property_names; |
363
|
|
|
|
|
|
|
|
364
|
906
|
|
|
|
|
1184
|
my @id_column_positions; |
365
|
906
|
|
|
|
|
1705
|
for my $id_property_name (@id_property_names) { |
366
|
1364
|
|
|
|
|
1538
|
for my $n (0..$#{ $template->{property_names} }) { |
|
1364
|
|
|
|
|
3703
|
|
367
|
3584
|
100
|
|
|
|
6310
|
if ($template->{property_names}[$n] eq $id_property_name) { |
368
|
1364
|
|
|
|
|
2138
|
push @id_column_positions, $template->{column_positions}[$n]; |
369
|
1364
|
|
|
|
|
1981
|
last; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
} |
373
|
906
|
|
|
|
|
1632
|
$template->{id_column_positions} = \@id_column_positions; |
374
|
|
|
|
|
|
|
|
375
|
906
|
100
|
|
|
|
2653
|
if (@id_column_positions == 1) { |
|
|
50
|
|
|
|
|
|
376
|
|
|
|
|
|
|
$template->{id_resolver} = sub { |
377
|
0
|
|
|
0
|
|
0
|
return $_[0][$id_column_positions[0]]; |
378
|
|
|
|
|
|
|
} |
379
|
679
|
|
|
|
|
3120
|
} |
380
|
|
|
|
|
|
|
elsif (@id_column_positions > 1) { |
381
|
227
|
|
|
|
|
464
|
my $class_name = $template->{data_class_name}; |
382
|
|
|
|
|
|
|
$template->{id_resolver} = sub { |
383
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
384
|
0
|
|
|
|
|
0
|
return $class_name->__meta__->resolve_composite_id_from_ordered_values(@$self[@id_column_positions]); |
385
|
|
|
|
|
|
|
} |
386
|
227
|
|
|
|
|
1481
|
} |
387
|
|
|
|
|
|
|
else { |
388
|
|
|
|
|
|
|
Carp::croak("Can't determine which columns will hold the ID property data for class " |
389
|
|
|
|
|
|
|
. $template->{data_class_name} . ". It's ID properties are (" . join(', ', @id_property_names) |
390
|
0
|
|
|
|
|
0
|
. ") which do not appear in the class' property list (" . join(', ', @{$template->{'property_names'}}).")"); |
|
0
|
|
|
|
|
0
|
|
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
906
|
|
|
|
|
1855
|
my $source_alias = $template->{table_alias}; |
394
|
906
|
|
|
|
|
1612
|
if (0 and my $join_data_for_source_table = $obj_joins_by_source_alias{$source_alias}) { |
395
|
|
|
|
|
|
|
# there are joins which come from this entity to other entities |
396
|
|
|
|
|
|
|
# as these entities are loaded, remember the individual queries covered by this object returning |
397
|
|
|
|
|
|
|
# NOTE: when we join a <> b, we remember that we've loaded all of the b for a when _a_ loads, not b, |
398
|
|
|
|
|
|
|
# since it's possible that there ar zero of b, and we don't want to perform the query for b |
399
|
|
|
|
|
|
|
my $source_object_num = $template->{object_num}; |
400
|
|
|
|
|
|
|
my $source_class_name = $template->{data_class_name}; |
401
|
|
|
|
|
|
|
my $next_joins = $template->{next_joins} ||= []; |
402
|
|
|
|
|
|
|
for my $foreign_alias (keys %$join_data_for_source_table) { |
403
|
|
|
|
|
|
|
my $foreign_object_num = $alias_object_num{$foreign_alias}; |
404
|
|
|
|
|
|
|
Carp::confess("no alias for $foreign_alias?") if not defined $foreign_object_num; |
405
|
|
|
|
|
|
|
my $foreign_template = $templates[$foreign_object_num]; |
406
|
|
|
|
|
|
|
my $foreign_class_name = $foreign_template->{data_class_name}; |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
my $join_data = $join_data_for_source_table->{$foreign_alias}; |
409
|
|
|
|
|
|
|
my %links = map { $_ ? @$_ : () } $join_data->{links}; |
410
|
|
|
|
|
|
|
my %filters = map { $_ ? @$_ : () } $join_data->{filters}; |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
my @keys = sort (keys %links, keys %filters); |
413
|
|
|
|
|
|
|
my @value_position_source_property; |
414
|
|
|
|
|
|
|
for (my $n = 0; $n < @keys; $n++) { |
415
|
|
|
|
|
|
|
my $key = $keys[$n]; |
416
|
|
|
|
|
|
|
if ($links{$key} and $filters{$key}) { |
417
|
|
|
|
|
|
|
Carp::confess("unexpected same key $key in filters and joins"); |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
my $source_property_name = $links{$key}; |
420
|
|
|
|
|
|
|
next unless $source_property_name; |
421
|
|
|
|
|
|
|
push @value_position_source_property, $n, $source_property_name; |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
my $bx = $foreign_class_name->define_boolexpr(map { $_ => $filters{$_} } @keys); |
424
|
|
|
|
|
|
|
my ($bxt, @values) = $bx->template_and_values(); |
425
|
|
|
|
|
|
|
push @$next_joins, [ $bxt->id, \@values, \@value_position_source_property ]; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
} |
429
|
|
|
|
|
|
|
|
430
|
785
|
|
|
|
|
3046
|
return \@templates; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub create_iterator_closure_for_rule_template_and_values { |
434
|
0
|
|
|
0
|
1
|
0
|
my ($self, $rule_template, @values) = @_; |
435
|
0
|
|
|
|
|
0
|
my $rule = $rule_template->get_rule_for_values(@values); |
436
|
0
|
|
|
|
|
0
|
return $self->create_iterator_closure_for_rule($rule); |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
sub _reclassify_object_loading_info_for_new_class { |
440
|
115
|
|
|
115
|
|
138
|
my $self = shift; |
441
|
115
|
|
|
|
|
130
|
my $loading_info = shift; |
442
|
115
|
|
|
|
|
138
|
my $new_class = shift; |
443
|
|
|
|
|
|
|
|
444
|
115
|
|
|
|
|
133
|
my $new_info; |
445
|
115
|
|
|
|
|
338
|
%$new_info = %$loading_info; |
446
|
|
|
|
|
|
|
|
447
|
115
|
|
|
|
|
247
|
foreach my $template_id (keys %$loading_info) { |
448
|
|
|
|
|
|
|
|
449
|
150
|
|
|
|
|
190
|
my $target_class_rules = $loading_info->{$template_id}; |
450
|
150
|
|
|
|
|
268
|
foreach my $rule_id (keys %$target_class_rules) { |
451
|
163
|
|
|
|
|
520
|
my $pos = index($rule_id,'/'); |
452
|
163
|
|
|
|
|
571
|
$new_info->{$template_id}->{$new_class . "/" . substr($rule_id,$pos+1)} = 1; |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
|
456
|
115
|
|
|
|
|
231
|
return $new_info; |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub _get_object_loading_info { |
460
|
115
|
|
|
115
|
|
174
|
my $self = shift; |
461
|
115
|
|
|
|
|
134
|
my $obj = shift; |
462
|
115
|
|
|
|
|
138
|
my %param_load_hash; |
463
|
115
|
50
|
|
|
|
298
|
if ($obj->{'__load'}) { |
464
|
115
|
|
|
|
|
150
|
while( my($template_id, $rules) = each %{ $obj->{'__load'} } ) { |
|
252
|
|
|
|
|
787
|
|
465
|
137
|
|
|
|
|
307
|
foreach my $rule_id ( keys %$rules ) { |
466
|
137
|
|
|
|
|
445
|
$param_load_hash{$template_id}->{$rule_id} = $UR::Context::all_params_loaded->{$template_id}->{$rule_id}; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
} |
470
|
115
|
|
|
|
|
285
|
return \%param_load_hash; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
sub _add_object_loading_info { |
475
|
56
|
|
|
56
|
|
79
|
my $self = shift; |
476
|
56
|
|
|
|
|
71
|
my $obj = shift; |
477
|
56
|
|
|
|
|
72
|
my $param_load_hash = shift; |
478
|
|
|
|
|
|
|
|
479
|
56
|
|
|
|
|
239
|
while( my($template_id, $rules) = each %$param_load_hash) { |
480
|
80
|
|
|
|
|
133
|
foreach my $rule_id ( keys %$rules ) { |
481
|
135
|
|
|
|
|
336
|
$obj->{'__load'}->{$template_id}->{$rule_id} = $rules->{$rule_id}; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
# same as add_object_loading_info, but manipulates the data in $UR::Context::all_params_loaded |
488
|
|
|
|
|
|
|
sub _record_that_loading_has_occurred { |
489
|
147
|
|
|
147
|
|
174
|
my $self = shift; |
490
|
147
|
|
|
|
|
172
|
my $param_load_hash = shift; |
491
|
|
|
|
|
|
|
|
492
|
147
|
|
|
|
|
487
|
while( my($template_id, $rules) = each %$param_load_hash) { |
493
|
186
|
|
|
|
|
301
|
foreach my $rule_id ( keys %$rules ) { |
494
|
|
|
|
|
|
|
$UR::Context::all_params_loaded->{$template_id}->{$rule_id} ||= |
495
|
301
|
|
100
|
|
|
1309
|
$rules->{$rule_id}; |
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
} |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
sub _first_class_in_inheritance_with_a_table { |
501
|
|
|
|
|
|
|
# This is called once per subclass and cached in the subclass from then on. |
502
|
78
|
|
|
78
|
|
106
|
my $self = shift; |
503
|
78
|
|
|
|
|
109
|
my $class = shift; |
504
|
78
|
50
|
|
|
|
191
|
$class = ref($class) if ref($class); |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
|
507
|
78
|
50
|
|
|
|
179
|
unless ($class) { |
508
|
0
|
|
|
|
|
0
|
Carp::confess("No class?"); |
509
|
|
|
|
|
|
|
} |
510
|
78
|
|
|
|
|
283
|
my $class_object = $class->__meta__; |
511
|
78
|
|
|
|
|
132
|
my $found = ""; |
512
|
78
|
|
|
|
|
458
|
for ($class_object, $class_object->ancestry_class_metas) |
513
|
|
|
|
|
|
|
{ |
514
|
139
|
100
|
|
|
|
676
|
if ($_->has_direct_table) |
515
|
|
|
|
|
|
|
{ |
516
|
78
|
|
|
|
|
233
|
$found = $_->class_name; |
517
|
78
|
|
|
|
|
142
|
last; |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
#eval qq/ |
521
|
|
|
|
|
|
|
# package $class; |
522
|
|
|
|
|
|
|
# sub _first_class_in_inheritance_with_a_table { |
523
|
|
|
|
|
|
|
# return '$found' if \$_[0] eq '$class'; |
524
|
|
|
|
|
|
|
# shift->SUPER::_first_class_in_inheritance_with_a_table(\@_); |
525
|
|
|
|
|
|
|
# } |
526
|
|
|
|
|
|
|
#/; |
527
|
|
|
|
|
|
|
#die "Error setting data in subclass: $@" if $@; |
528
|
78
|
|
|
|
|
210
|
return $found; |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
sub _class_is_safe_to_rebless_from_parent_class { |
532
|
78
|
|
|
78
|
|
155
|
my ($self, $class, $was_loaded_as_this_parent_class) = @_; |
533
|
78
|
|
|
|
|
391
|
my $fcwt = $self->_first_class_in_inheritance_with_a_table($class); |
534
|
78
|
50
|
|
|
|
206
|
unless ($fcwt) { |
535
|
0
|
|
|
|
|
0
|
Carp::croak("Can't call _class_is_safe_to_rebless_from_parent_class(): Class $class has no parent classes with a table"); |
536
|
|
|
|
|
|
|
} |
537
|
78
|
|
|
|
|
427
|
return ($was_loaded_as_this_parent_class->isa($fcwt)); |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
sub ur_datasource_class_for_dbi_connect_string { |
541
|
70
|
|
|
70
|
0
|
99
|
my($class, $dsn) = @_; |
542
|
70
|
|
|
|
|
398
|
my(undef, $driver) = DBI->parse_dsn($dsn); |
543
|
70
|
50
|
|
|
|
1379
|
$driver |
544
|
|
|
|
|
|
|
|| Carp::croak("Could not parse DBI driver out of connect string $dsn"); |
545
|
70
|
|
|
|
|
213
|
return 'UR::DataSource::'.$driver; |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
sub _get_current_entities { |
549
|
125
|
|
|
125
|
|
195
|
my $self = shift; |
550
|
125
|
|
|
|
|
587
|
my @class_meta = UR::Object::Type->is_loaded( |
551
|
|
|
|
|
|
|
data_source_id => $self->id |
552
|
|
|
|
|
|
|
); |
553
|
125
|
|
|
|
|
228
|
my @objects; |
554
|
125
|
|
|
|
|
256
|
for my $class_meta (@class_meta) { |
555
|
308
|
50
|
|
|
|
1112
|
next unless $class_meta->generated(); # Ungenerated classes won't have any instances |
556
|
308
|
|
|
|
|
558
|
my $class_name = $class_meta->class_name; |
557
|
308
|
|
|
|
|
570
|
push @objects, $UR::Context::current->all_objects_loaded($class_name); |
558
|
|
|
|
|
|
|
} |
559
|
125
|
|
|
|
|
1229
|
return @objects; |
560
|
|
|
|
|
|
|
} |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
|
563
|
|
|
|
0
|
|
|
sub _prepare_for_lob { }; |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
sub _set_specified_objects_saved_uncommitted { |
566
|
52
|
|
|
52
|
|
104
|
my ($self,$objects_arrayref) = @_; |
567
|
|
|
|
|
|
|
# Sets an objects as though the has been saved but tha changes have not been committed. |
568
|
|
|
|
|
|
|
# This is called automatically by _sync_databases. |
569
|
|
|
|
|
|
|
|
570
|
52
|
|
|
|
|
92
|
my %objects_by_class; |
571
|
|
|
|
|
|
|
my $class_name; |
572
|
52
|
|
|
|
|
139
|
for my $object (@$objects_arrayref) { |
573
|
134
|
|
|
|
|
216
|
$class_name = ref($object); |
574
|
134
|
|
100
|
|
|
475
|
$objects_by_class{$class_name} ||= []; |
575
|
134
|
|
|
|
|
122
|
push @{ $objects_by_class{$class_name} }, $object; |
|
134
|
|
|
|
|
255
|
|
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
|
578
|
52
|
|
|
|
|
230
|
for my $class_name (sort keys %objects_by_class) { |
579
|
72
|
|
|
|
|
348
|
my $class_object = $class_name->__meta__; |
580
|
|
|
|
|
|
|
my @property_names = |
581
|
246
|
|
|
|
|
411
|
map { $_->property_name } |
582
|
72
|
|
|
|
|
574
|
grep { $_->column_name } |
|
371
|
|
|
|
|
624
|
|
583
|
|
|
|
|
|
|
$class_object->all_property_metas; |
584
|
|
|
|
|
|
|
|
585
|
72
|
|
|
|
|
142
|
for my $object (@{ $objects_by_class{$class_name} }) { |
|
72
|
|
|
|
|
189
|
|
586
|
134
|
|
100
|
|
|
562
|
$object->{db_saved_uncommitted} ||= {}; |
587
|
134
|
|
|
|
|
183
|
my $db_saved_uncommitted = $object->{db_saved_uncommitted}; |
588
|
134
|
|
|
|
|
167
|
for my $property ( @property_names ) { |
589
|
464
|
|
|
|
|
996
|
$db_saved_uncommitted->{$property} = $object->$property; |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
} |
593
|
52
|
|
|
|
|
283
|
return 1; |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
sub _set_all_objects_saved_committed { |
597
|
|
|
|
|
|
|
# called by UR::DBI on commit |
598
|
103
|
|
|
103
|
|
174
|
my $self = shift; |
599
|
103
|
|
|
|
|
1204
|
return $self->_set_specified_objects_saved_committed([ $self->_get_current_entities ]); |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
sub _set_all_specified_objects_saved_committed { |
603
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
604
|
0
|
|
|
|
|
0
|
my($pkg, $file, $line) = caller; |
605
|
0
|
|
|
|
|
0
|
Carp::carp("Deprecated method _set_all_specified_objects_saved_committed called at file $file line $line. The new name for this method is _set_specified_objects_saved_committed"); |
606
|
0
|
|
|
|
|
0
|
my @changed_objects = @_; |
607
|
0
|
|
|
|
|
0
|
$self->_set_specified_objects_saved_committed(\@changed_objects); |
608
|
|
|
|
|
|
|
} |
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub _set_specified_objects_saved_committed { |
611
|
108
|
|
|
108
|
|
186
|
my $self = shift; |
612
|
108
|
|
|
|
|
141
|
my $objects = shift; |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
# Two step process... set saved and committed, then fire commit observers. |
615
|
|
|
|
|
|
|
# Doing so prevents problems should any of the observers themselves commit. |
616
|
108
|
|
|
|
|
135
|
my @saved_objects; |
617
|
108
|
|
|
|
|
208
|
for my $obj (@$objects) { |
618
|
677
|
|
|
|
|
900
|
my $saved = $self->_set_object_saved_committed($obj); |
619
|
677
|
100
|
|
|
|
948
|
push @saved_objects, $saved if $saved; |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
|
622
|
108
|
|
|
|
|
205
|
for my $obj (@saved_objects) { |
623
|
83
|
100
|
|
|
|
338
|
next if $obj->isa('UR::DeletedRef'); |
624
|
80
|
|
|
|
|
242
|
$obj->__signal_change__('commit'); |
625
|
80
|
100
|
|
|
|
312
|
if ($obj->isa('UR::Object::Ghost')) { |
626
|
20
|
|
|
|
|
67
|
$UR::Context::current->_abandon_object($obj); |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
} |
629
|
|
|
|
|
|
|
|
630
|
108
|
|
100
|
|
|
940
|
return scalar(@$objects) || "0 but true"; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
sub _set_object_saved_committed { |
634
|
|
|
|
|
|
|
# called by the above, and some test cases |
635
|
677
|
|
|
677
|
|
506
|
my ($self, $object) = @_; |
636
|
677
|
100
|
|
|
|
851
|
if ($object->{db_saved_uncommitted}) { |
637
|
83
|
100
|
|
|
|
394
|
unless ($object->isa('UR::Object::Ghost')) { |
638
|
60
|
|
|
|
|
1928
|
%{ $object->{db_committed} } = ( |
639
|
24
|
|
|
|
|
92
|
($object->{db_committed} ? %{ $object->{db_committed} } : ()), |
640
|
60
|
100
|
|
|
|
134
|
%{ $object->{db_saved_uncommitted} } |
|
60
|
|
|
|
|
153
|
|
641
|
|
|
|
|
|
|
); |
642
|
60
|
|
|
|
|
166
|
delete $object->{db_saved_uncommitted}; |
643
|
|
|
|
|
|
|
} |
644
|
83
|
|
|
|
|
119
|
return $object; |
645
|
|
|
|
|
|
|
} |
646
|
|
|
|
|
|
|
else { |
647
|
594
|
|
|
|
|
482
|
return; |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
} |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
sub _set_all_objects_saved_rolled_back { |
652
|
|
|
|
|
|
|
# called by UR::DBI on commit |
653
|
22
|
|
|
22
|
|
26
|
my $self = shift; |
654
|
22
|
|
|
|
|
74
|
my @objects = $self->_get_current_entities; |
655
|
22
|
|
|
|
|
55
|
for my $obj (@objects) { |
656
|
203
|
50
|
|
|
|
226
|
unless ($self->_set_object_saved_rolled_back($obj)) { |
657
|
0
|
|
|
|
|
0
|
die "An error occurred setting " . $obj->__display_name__ |
658
|
|
|
|
|
|
|
. " to match the rolled-back database state. Exiting..."; |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
sub _set_specified_objects_saved_rolled_back { |
664
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
665
|
0
|
|
|
|
|
0
|
my $objects = shift; |
666
|
0
|
|
|
|
|
0
|
for my $obj (@$objects) { |
667
|
0
|
0
|
|
|
|
0
|
unless ($self->_set_object_saved_rolled_back($obj)) { |
668
|
0
|
|
|
|
|
0
|
die "An error occurred setting " . $obj->__display_name__ |
669
|
|
|
|
|
|
|
. " to match the rolled-back database state. Exiting..."; |
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
sub _set_object_saved_rolled_back { |
677
|
|
|
|
|
|
|
# called by the above, and some test cases |
678
|
203
|
|
|
203
|
|
127
|
my ($self,$object) = @_; |
679
|
203
|
|
|
|
|
156
|
delete $object->{db_saved_uncommitted}; |
680
|
203
|
|
|
|
|
335
|
return $object; |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
# These are part of the basic DataSource API. Subclasses will want to override these |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
sub _sync_database { |
687
|
0
|
|
|
0
|
|
0
|
my $class = shift; |
688
|
0
|
|
|
|
|
0
|
my %args = @_; |
689
|
0
|
|
0
|
|
|
0
|
$class = ref($class) || $class; |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
$class->warning_message("Data source $class does not support saving objects to storage. " . |
692
|
0
|
|
|
|
|
0
|
scalar(@{$args{'changed_objects'}}) . " objects will not be saved"); |
|
0
|
|
|
|
|
0
|
|
693
|
0
|
|
|
|
|
0
|
return 1; |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
sub commit { |
697
|
5
|
|
|
5
|
1
|
6
|
my $class = shift; |
698
|
5
|
|
|
|
|
6
|
my %args = @_; |
699
|
5
|
|
33
|
|
|
14
|
$class = ref($class) || $class; |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
#$class->warning_message("commit() ignored for data source $class"); |
702
|
5
|
|
|
|
|
9
|
return 1; |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
sub rollback { |
706
|
0
|
|
|
0
|
1
|
0
|
my $class = shift; |
707
|
0
|
|
|
|
|
0
|
my %args = @_; |
708
|
0
|
|
0
|
|
|
0
|
$class = ref($class) || $class; |
709
|
|
|
|
|
|
|
|
710
|
0
|
|
|
|
|
0
|
$class->warning_message("rollback() ignored for data source $class"); |
711
|
0
|
|
|
|
|
0
|
return 1; |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
# When the class initializer is create property objects, it will |
715
|
|
|
|
|
|
|
# auto-fill-in column_name if the class definition has a table_name. |
716
|
|
|
|
|
|
|
# File-based data sources do not have tables (and so classes using them |
717
|
|
|
|
|
|
|
# do not have table_names), but the properties still need column_names |
718
|
|
|
|
|
|
|
# so loading works properly. |
719
|
|
|
|
|
|
|
# For now, only UR::DataSource::File and ::FileMux set this. |
720
|
|
|
|
|
|
|
# FIXME this method's existence is ugly. Find a better way to fill in |
721
|
|
|
|
|
|
|
# column_name for those properties, or fix the data sources to not |
722
|
|
|
|
|
|
|
# require column_names to be set by the initializer |
723
|
|
|
|
|
|
|
sub initializer_should_create_column_name_for_class_properties { |
724
|
2053
|
|
|
2053
|
0
|
8438
|
return 0; |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
# Subclasses should override this. |
729
|
|
|
|
|
|
|
# It's called by the class initializer when the data_source property in a class |
730
|
|
|
|
|
|
|
# definition contains a hashref with an 'is' key. The method should accept this |
731
|
|
|
|
|
|
|
# hashref, create a data_source instance (if appropriate) and return the class_name |
732
|
|
|
|
|
|
|
# of this new datasource. |
733
|
|
|
|
|
|
|
sub create_from_inline_class_data { |
734
|
0
|
|
|
0
|
1
|
0
|
my ($class,$class_data,$ds_data) = @_; |
735
|
0
|
|
|
|
|
0
|
my %ds_data = %$ds_data; |
736
|
0
|
|
|
|
|
0
|
my $ds_class_name = delete $ds_data{is}; |
737
|
0
|
0
|
|
|
|
0
|
unless (my $ds_class_meta = UR::Object::Type->get($ds_class_name)) { |
738
|
0
|
|
|
|
|
0
|
die "No class $ds_class_name found!"; |
739
|
|
|
|
|
|
|
} |
740
|
0
|
|
|
|
|
0
|
my $ds = $ds_class_name->__define__(%ds_data); |
741
|
0
|
0
|
|
|
|
0
|
unless ($ds) { |
742
|
0
|
|
|
|
|
0
|
die "Failed to construct $ds_class_name: " . $ds_class_name->error_message(); |
743
|
|
|
|
|
|
|
} |
744
|
0
|
|
|
|
|
0
|
return $ds; |
745
|
|
|
|
|
|
|
} |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
sub ur_data_type_for_data_source_data_type { |
748
|
0
|
|
|
0
|
0
|
0
|
my($class,$type) = @_; |
749
|
|
|
|
|
|
|
|
750
|
0
|
|
|
|
|
0
|
return [undef,undef]; # The default that should give reasonable behavior |
751
|
|
|
|
|
|
|
} |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
# prepare_for_fork, do_after_fork_in_child, and finish_up_after_fork are no-op |
755
|
|
|
|
|
|
|
# here in the UR::DataSource base class and should be implented in subclasses |
756
|
|
|
|
|
|
|
# as needed. |
757
|
2
|
|
|
2
|
0
|
6
|
sub prepare_for_fork { return 1 } |
758
|
2
|
|
|
2
|
0
|
14
|
sub do_after_fork_in_child { return 1 } |
759
|
2
|
|
|
2
|
0
|
20
|
sub finish_up_after_fork { return 1 } |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
sub _resolve_owner_and_table_from_table_name { |
762
|
546
|
|
|
546
|
|
486
|
my($self, $table_name) = @_; |
763
|
|
|
|
|
|
|
# Basic data sources don't know about owners/schemas |
764
|
546
|
|
|
|
|
893
|
return (undef, $table_name); |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
sub _resolve_table_and_column_from_column_name { |
768
|
546
|
|
|
546
|
|
712
|
my($self, $column_name) = @_; |
769
|
|
|
|
|
|
|
# Basic data sources don't know about tables |
770
|
546
|
|
|
|
|
1077
|
return (undef,$column_name); |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
1; |