line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Class::ReluctantORM::Driver; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Class::ReluctantORM::Driver - Abstract interface for RDBMSs |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 SYNOPSIS |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# ---- Driver Creation ---- |
10
|
|
|
|
|
|
|
# Driver instantiation is usually implicit |
11
|
|
|
|
|
|
|
MyClass->build_class($dbh => $some_database_handle); |
12
|
|
|
|
|
|
|
$driver = MyClass->driver(); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# To do it explicitly... |
15
|
|
|
|
|
|
|
# Create a raw database connection (or use a Class::ReluctantORM::DBH subclass) |
16
|
|
|
|
|
|
|
my $dbh = DBI->connect(...); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Now make a driver from the handle. The $dbh will |
19
|
|
|
|
|
|
|
# be checked for its RDBMS brand and version, and the |
20
|
|
|
|
|
|
|
# best-matching Driver subclass will be used. |
21
|
|
|
|
|
|
|
my $driver = Class::ReluctantORM::Driver->make_driver($cro_class, $dbh); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# ---- SQL Parsing ---- |
24
|
|
|
|
|
|
|
if ($driver->supports_parsing()) { |
25
|
|
|
|
|
|
|
$sql_obj = $driver->parse_statement("SELECT foo FROM bar WHERE baz = 'beep'"); |
26
|
|
|
|
|
|
|
$sql_where = $driver->parse_where("baz = 'beep'"); |
27
|
|
|
|
|
|
|
$sql_order_by = $driver->parse_order_by("dog DESC"); |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# ---- SQL Rendering ---- |
31
|
|
|
|
|
|
|
$sql_string = $driver->render($sql_obj, $hints); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# ---- SQL Execution ---- |
34
|
|
|
|
|
|
|
$driver->run_sql($sql_obj); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# If you like prepare-execute cycles... |
37
|
|
|
|
|
|
|
$driver->prepare($sql_obj); |
38
|
|
|
|
|
|
|
if ($sql_obj->is_prepared()) { |
39
|
|
|
|
|
|
|
$sql_obj->execute(@bindings); # Use output columns or callback to fetch results |
40
|
|
|
|
|
|
|
$sql_obj->finish(); |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# Or just get the DBI dbh and bang on it directly |
44
|
|
|
|
|
|
|
my $dbi_dbh = $driver->dbi_dbh(); |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=cut |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=for vaporware |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# (normally in autocommit mode) |
51
|
|
|
|
|
|
|
if ($driver->supports_transactions()) { |
52
|
|
|
|
|
|
|
$driver->begin_transaction(); |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Do things.... |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
if ($driver->is_in_transaction()) { ... } |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
if (...) { |
59
|
|
|
|
|
|
|
$driver->commit_transaction(); |
60
|
|
|
|
|
|
|
} else { |
61
|
|
|
|
|
|
|
$driver->rollback_transaction(); |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
# Returns to autocommit after a call to either commit or rollback |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=cut |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=pod |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# ---- DB MetaData and SQL String Utils ---- |
72
|
|
|
|
|
|
|
$field2column_map = $driver->read_fields($schema, $table); # May be cached |
73
|
|
|
|
|
|
|
@columns = $driver->find_primary_key_columns($schema, $table); # May be cached |
74
|
|
|
|
|
|
|
$char = $driver->open_quote(); |
75
|
|
|
|
|
|
|
$char = $driver->close_quote(); |
76
|
|
|
|
|
|
|
$char = $driver->name_separator(); |
77
|
|
|
|
|
|
|
$str = $driver->table_case($name); |
78
|
|
|
|
|
|
|
$str = $driver->schema_case($name); |
79
|
|
|
|
|
|
|
$str = $driver->column_case($name); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head1 DESCRIPTION |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
The Driver facility provides RDBMS-specific dialect support. In other words, high-level methods (like reading a list of fields in a table) are available via any Driver, while behind the scenes a Driver subclass is speaking a particular dialect to your database handle. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Drivers provide five major groups of functionality: |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=over |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
=item Database metadata access |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
List columns, keys, etc. This area is immature. |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=item SQL Generation |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
Transform a CRO SQL object into a SQL string in the driver's dialect. See render() |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=item SQL Execution |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Using the Class::ReluctantORM::DBH, execute SQL strings on the database and retrieve the results. See prepare() |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=item SQL Parsing |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
Transform a SQL string in the Driver's dialect into a CRO SQL object for later manipulation. Such support is just out of its infancy - call it toddler-dom. See supports_parsing(), parse_statement(), and parse_where(). |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=item Monitor Support |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
Drivers are the internal attachment point for Monitors, which are used to track database access. |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=back |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
This page documents the Driver superclass, which specifies the API provided by all drivers. See the individual drivers to learn more about their idiosyncracies (eg Class::ReluctantORM::Driver::PostgreSQL). |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
Each Class::ReluctantORM subclass has its own Driver (this allows different classes to originate from different databases). It is expected that you will re-use database handles across multiple drivers, however. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=head1 METHODS TO OVERRIDE WHEN SUBCLASSING |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
When creating an RDBMS-specific subclass, you will need to override the following methods: |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=over |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item aptitude |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item init |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=item read_fields |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item find_primary_key_columns |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=item run_sql |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=item execute_fetch_deep |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=item render |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item prepare |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=item supports_parsing |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=item parse_statement |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item parse_where |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=item parse_order_by |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=back |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=cut |
148
|
|
|
|
|
|
|
|
149
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
150
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
24
|
|
151
|
1
|
|
|
1
|
|
1358
|
use DBI::Const::GetInfoType; |
|
1
|
|
|
|
|
8973
|
|
|
1
|
|
|
|
|
183
|
|
152
|
1
|
|
|
1
|
|
10
|
use Scalar::Util qw(blessed weaken); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
116
|
|
153
|
1
|
|
|
1
|
|
9
|
use Class::ReluctantORM::Utilities qw(conditional_load_subdir); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
53
|
|
154
|
1
|
|
|
1
|
|
5
|
use Data::Dumper; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
79
|
|
155
|
|
|
|
|
|
|
|
156
|
1
|
|
|
1
|
|
800
|
use Class::ReluctantORM::Monitor; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
8
|
|
157
|
1
|
|
|
1
|
|
726
|
use Class::ReluctantORM::SQL::Aliases; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
157
|
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
our $DEBUG = 0; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
our @DRIVERS; |
162
|
|
|
|
|
|
|
BEGIN { |
163
|
1
|
|
|
1
|
|
5
|
@DRIVERS = conditional_load_subdir(__PACKAGE__); |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
=head1 INSTANCE METHODS |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=cut |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=head2 $dbh = $driver->cro_dbh(); |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Returns the Class::ReluctantORM::DBH object that provides low-level connectivity. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=cut |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub cro_dbh { |
178
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
179
|
|
|
|
|
|
|
|
180
|
0
|
0
|
|
|
|
|
if ($self->{db_class}) { |
181
|
|
|
|
|
|
|
# Call new() and return whatever we get back - this allows for connection pooling |
182
|
0
|
|
|
|
|
|
return $self->{db_class}->new(); |
183
|
|
|
|
|
|
|
} else { |
184
|
|
|
|
|
|
|
# Bare handle? |
185
|
0
|
|
|
|
|
|
return $self->{dbh}; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head2 $dbh = $driver->dbi_dbh(); |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Returns a DBI database handle. If the Class::ReluctantORM::DBH object is not based on DBI, this will be undef. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=cut |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub dbi_dbh { |
196
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
197
|
0
|
|
|
|
|
|
return $self->cro_dbh()->dbi_dbh(); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# awful old name |
201
|
0
|
|
|
0
|
0
|
|
sub dbh { return $_[0]->cro_dbh(); } |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# TODO DOCS |
204
|
0
|
|
|
0
|
0
|
|
sub open_quote { return '"'; } |
205
|
0
|
|
|
0
|
0
|
|
sub close_quote { return '"'; } |
206
|
0
|
|
|
0
|
0
|
|
sub name_separator { return '.'; } |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head2 $bool = $driver->supports_namespaces() |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Returns true if the driver supports namespaces (schemae - containers within a database for tables). If so, you can use name_separator to construct fully qualified table names. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Default implementation returns false. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=cut |
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
0
|
1
|
|
sub supports_namespaces { return 0; } |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
#==================================================================# |
221
|
|
|
|
|
|
|
# Protected Methods |
222
|
|
|
|
|
|
|
#==================================================================# |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub _install_dbh_error_trap { |
225
|
0
|
|
|
0
|
|
|
my $inv = shift; |
226
|
0
|
|
|
|
|
|
my $dbh = shift; |
227
|
0
|
|
|
|
|
|
$dbh->set_handle_error(Class::ReluctantORM::Exception->make_db_error_handler()); |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub _new { |
231
|
0
|
|
|
0
|
|
|
my $class = shift; |
232
|
0
|
|
|
|
|
|
my ($tb_class, $dbh, $dbclass, $brand, $version) = @_; |
233
|
0
|
|
|
|
|
|
my $self = bless { |
234
|
|
|
|
|
|
|
tb_class => $tb_class, |
235
|
|
|
|
|
|
|
dbh => $dbh, |
236
|
|
|
|
|
|
|
db_class => $dbclass, |
237
|
|
|
|
|
|
|
brand => $brand, |
238
|
|
|
|
|
|
|
version => $version, |
239
|
|
|
|
|
|
|
monitors => [], |
240
|
|
|
|
|
|
|
}, $class; |
241
|
0
|
0
|
|
|
|
|
if ($dbh) { weaken($self->{dbh}); } |
|
0
|
|
|
|
|
|
|
242
|
0
|
|
|
|
|
|
$self->init(); |
243
|
0
|
|
|
|
|
|
return $self; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
#==================================================================# |
247
|
|
|
|
|
|
|
# DRIVER SETUP |
248
|
|
|
|
|
|
|
#==================================================================# |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=head1 DRIVER SETUP METHODS |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=cut |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head2 $driver = Class::ReluctantORM::Driver->make_driver($cro_class, $dbhandle, $dbclass); |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Searches for the best available driver for the given database handle. The Class::ReluctantORM subclass name is passed for advisory purposes to the underlying driver subclass. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=cut |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
my %DBMS_INFO_CACHE; |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub make_driver { |
264
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
265
|
0
|
|
|
|
|
|
my $cro_class = shift; |
266
|
0
|
|
|
|
|
|
my $dbh = shift; |
267
|
0
|
|
|
|
|
|
my $dbclass = shift; |
268
|
|
|
|
|
|
|
|
269
|
0
|
|
|
|
|
|
$dbh = Class::ReluctantORM::DBH->_boost_to_cro_dbh($dbh); |
270
|
0
|
|
|
|
|
|
$class->_install_dbh_error_trap($dbh); |
271
|
0
|
|
0
|
|
|
|
my $brand = $DBMS_INFO_CACHE{$dbh->dbi_dbh}{SQL_DBMS_NAME} ||= $dbh->get_info($GetInfoType{SQL_DBMS_NAME}); # Expensive call, which will not change for the specific dbh |
272
|
0
|
|
0
|
|
|
|
my $version = $DBMS_INFO_CACHE{$dbh->dbi_dbh}{SQL_DBMS_VER} ||= $dbh->get_info($GetInfoType{SQL_DBMS_VER}); # Expensive call, which will not change for the specific dbh |
273
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
|
my @scores = sort { $b->[1] <=> $a->[1] } map { [ $_, $_->aptitude($brand, $version) ] } @DRIVERS; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
|
276
|
0
|
0
|
|
|
|
|
if ($DEBUG > 1) { |
277
|
0
|
|
|
|
|
|
print STDERR __PACKAGE__ . ':' . __LINE__ . " - have make_driver scores for $brand, $version:\n" . Dumper(\@scores); |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
0
|
0
|
|
|
|
|
if ($scores[0][1] < 0.5) { |
281
|
0
|
|
|
|
|
|
warn("For database $brand $version, no suitable Class::ReluctantORM::Driver could be found. Using $scores[0][0] (score: $scores[0][1])"); |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
0
|
|
|
|
|
|
my $impl_class = $scores[0][0]; |
285
|
0
|
|
|
|
|
|
my $self = $impl_class->_new($cro_class, $dbh, $dbclass, $brand, $version); |
286
|
|
|
|
|
|
|
|
287
|
0
|
|
|
|
|
|
return $self; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
=head2 $n = $class->aptitude($brand, $version); |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
Should return a number between 0 and 1 indicating how well the |
293
|
|
|
|
|
|
|
driver can handle the given type of database server. Scores less than 0.5 |
294
|
|
|
|
|
|
|
are considered ill-equipped. The highest-scoring driver will be used. |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
Default implementation returns 0. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=cut |
300
|
|
|
|
|
|
|
|
301
|
0
|
|
|
0
|
1
|
|
sub aptitude { return 0; } |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=head2 $driver->init(); |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
Called with no args just after driver construction. The dbh is |
306
|
|
|
|
|
|
|
available at this point. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
Default implementation does nothing. |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=cut |
311
|
|
|
|
|
|
|
|
312
|
0
|
|
|
0
|
1
|
|
sub init {} |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
#==================================================================# |
316
|
|
|
|
|
|
|
# DB METADATA |
317
|
|
|
|
|
|
|
#==================================================================# |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=head1 DATABASE METADATA METHODS |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
=cut |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=head2 $version_string = $driver->server_brand(); |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Returns the vendor-specific brand name (cached from Driver creation, the result of a DBI get_info SQL_DBMS_NAME call). |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=cut |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub server_brand { |
330
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
331
|
0
|
|
|
|
|
|
return $driver->{brand}; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=head2 $version_string = $driver->server_version(); |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
Returns the vendor-specific version string (cached from Driver creation, the result of a DBI get_info SQL_DBMS_VER call). |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
=cut |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub server_version { |
341
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
342
|
0
|
|
|
|
|
|
return $driver->{version}; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
=head2 $field2column_map = $driver->read_fields($schema_name, $table_name); |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
Scans the associated table for columns, and returns a hash mapping |
350
|
|
|
|
|
|
|
lowercased field named to database case column names. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
This data may be cached. See the Class::ReluctantORM global option schema_cache_policy, and the Class::ReluctantORM::SchemaCache . |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
Default implementation throws a PureVirtual exception. You must override this method. |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=cut |
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
0
|
1
|
|
sub read_fields { Class::ReluctantORM::Exception::Call::PureVirtual->croak(); } |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=head2 @cols = $driver->find_primary_key_columns(); |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
Returns a list of columns used in the table's primary key. This is |
363
|
|
|
|
|
|
|
usually a one-item list. |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
This data may be cached. See the Class::ReluctantORM global option schema_cache_policy, and Class::ReluctantORM::SchemaCache . |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
Default implementation throws a PureVirtual exception. You must override this method. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut |
370
|
|
|
|
|
|
|
|
371
|
0
|
|
|
0
|
1
|
|
sub find_primary_key_columns { Class::ReluctantORM::Exception::Call::PureVirtual->croak(); } |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head2 $str = $driver->schema_case($str); |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head2 $str = $driver->table_case($str); |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head2 $str = $driver->column_case($str); |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Adjusts the given string to be in the case expected by the driver for the given object type. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
Default implementation is to lowercase everything. |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=cut |
384
|
|
|
|
|
|
|
|
385
|
0
|
|
|
0
|
1
|
|
sub schema_case { return lc($_[1]); } |
386
|
0
|
|
|
0
|
1
|
|
sub table_case { return lc($_[1]); } |
387
|
0
|
|
|
0
|
1
|
|
sub column_case { return lc($_[1]); } |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
#==================================================================# |
390
|
|
|
|
|
|
|
# SQL EXECUTION |
391
|
|
|
|
|
|
|
#==================================================================# |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head1 SQL EXECUTION SUPPORT |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
These methods provide the rendering and execution capabilities of the driver. |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=head2 Execution Hinting |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
Most of the execution support methods accept an optional hashref that provides hints for the driver. Currently supported hints: |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=over |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=item already_transformed |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
Boolean, default false. If true, indicates that the given SQL object has already been through its transformation phase, and should not be trnasformed again. |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=back |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
Specific drivers may extend this list. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=cut |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=head2 $driver->run_sql($sql, $hints); |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
Executes the given SQL object. The SQL object then contains |
418
|
|
|
|
|
|
|
the results; you can also use the $sql->add_fetchrow_listener() method to add a hook. |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
The 'hints' arg is optional, and is a hashref as specified in EXECUTION HINTING. |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
A reasonable default implementation is provided. |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=cut |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
sub run_sql { |
427
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
428
|
0
|
|
|
|
|
|
my $sql = shift; |
429
|
0
|
|
|
|
|
|
my $hints = shift; |
430
|
|
|
|
|
|
|
|
431
|
0
|
|
|
|
|
|
$driver->prepare($sql, $hints); |
432
|
0
|
|
|
|
|
|
my $sth = $sql->_sth(); |
433
|
0
|
|
|
|
|
|
my $str = $sql->_sql_string(); |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# OK, run the query |
436
|
0
|
|
|
|
|
|
my @binds = $sql->get_bind_values(); |
437
|
0
|
|
|
|
|
|
$driver->_monitor_execute_begin(sql_obj => $sql, sql_str => $str, binds => \@binds, sth => $sth); |
438
|
0
|
|
|
|
|
|
eval { |
439
|
0
|
|
|
|
|
|
$sth = $driver->cro_dbh->execute($sth, @binds); |
440
|
|
|
|
|
|
|
}; |
441
|
0
|
0
|
|
|
|
|
if ($@) { |
442
|
|
|
|
|
|
|
# Rethrow so we have CRO tracing |
443
|
0
|
|
|
|
|
|
Class::ReluctantORM::SchemaCache->instance->notify_sql_error($@); |
444
|
0
|
|
|
|
|
|
Class::ReluctantORM::Exception::SQL::ExecutionError->croak(error => $@); |
445
|
|
|
|
|
|
|
} |
446
|
0
|
|
|
|
|
|
$driver->_monitor_execute_finish(sql_obj => $sql, sql_str => $str, binds => \@binds, sth => $sth); |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# Fetch the result, if any |
449
|
0
|
0
|
|
|
|
|
if ($sql->output_columns) { |
450
|
0
|
|
|
|
|
|
while (my $row = $sth->fetchrow_hashref()) { |
451
|
0
|
|
|
|
|
|
$driver->_monitor_fetch_row(sql_obj => $sql, sql_str => $str, binds => \@binds, sth => $sth, row => $row); |
452
|
0
|
|
|
|
|
|
$sql->set_single_row_results($row); |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
} |
455
|
0
|
|
|
|
|
|
$sth->finish(); |
456
|
0
|
|
|
|
|
|
$driver->_monitor_finish(sql_obj => $sql, sql_str => $str, sth => $sth); |
457
|
|
|
|
|
|
|
|
458
|
0
|
|
|
|
|
|
return 1; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=head2 @results = $driver->execute_fetch_deep($sql_obj); |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
Renders, executes, and parses the results of a "fetch deep" style SQL query. Internally, this may be the same as run_sql; but some drivers may need to perform extra transformations for fetch deep (to allow use of LIMIT clauses, for example). |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=cut |
467
|
|
|
|
|
|
|
|
468
|
0
|
|
|
0
|
1
|
|
sub execute_fetch_deep { Class::ReluctantORM::Exception::Call::PureVirtual->croak(); } |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=head2 $str = $driver->render($sql_obj, $hints); |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
Takes a Class::ReluctantORM::SQL object, and renders it down to a SQL string. |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
The 'hints' arg is optional, and is a hashref as specified in EXECUTION HINTING. |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=cut |
477
|
|
|
|
|
|
|
|
478
|
0
|
|
|
0
|
1
|
|
sub render { Class::ReluctantORM::Exception::Call::PureVirtual->croak(); } |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=head2 $sth = $driver->prepare($sql_obj, $hints); |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Renders the SQL object to a SQL string, then passes it through the underlying DBI dbh, and returns the resulting statement handle. You can then use either $sql_obj->execute() or if you prefer a lower-level approach, you can operate directly on the statement handle. |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
The 'hints' arg is optional, and is a hashref as specified in EXECUTION HINTING. |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
A reasonable default implementation is provided. |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=cut |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub prepare { |
491
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
492
|
0
|
|
|
|
|
|
my $sql = shift; |
493
|
0
|
|
|
|
|
|
my $hints = shift; |
494
|
|
|
|
|
|
|
|
495
|
0
|
|
|
|
|
|
$driver->render($sql); |
496
|
0
|
|
|
|
|
|
my $sth = $driver->cro_dbh->prepare($sql->_sql_string()); |
497
|
0
|
|
|
|
|
|
$sql->_sth($sth); |
498
|
|
|
|
|
|
|
|
499
|
0
|
|
|
|
|
|
return $sth; |
500
|
|
|
|
|
|
|
} |
501
|
|
|
|
|
|
|
|
502
|
0
|
|
|
0
|
|
|
sub _pre_execute_hook { } |
503
|
0
|
|
|
0
|
|
|
sub _post_execute_hook { } |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
#==================================================================# |
506
|
|
|
|
|
|
|
# TRANSACTION SUPPORT |
507
|
|
|
|
|
|
|
#==================================================================# |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# TODO - transaction support |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
#==================================================================# |
512
|
|
|
|
|
|
|
# PARSING SUPPORT |
513
|
|
|
|
|
|
|
#==================================================================# |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
=head2 $bool = $driver->supports_parsing(); |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
Returns true if you can call parse_statement() or parse_where() and expect it to possibly work. |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
Default implementation returns false. |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=cut |
522
|
|
|
|
|
|
|
|
523
|
0
|
|
|
0
|
1
|
|
sub supports_parsing { return 0; } |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
=head2 $sql_obj = $driver->parse_statement($sql_string, $options); |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
EXERIMENTAL |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
Examines the $sql_string, and builds a Class::ReluctantORM::SQL object that semantically represents the statement. Syntax details will not be preserved - you can't round-trip this. |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
If a problem occurs, an exception will be thrown, either Class::ReluctantORM::Exception::SQL::ParseError (your fault for sending garbage) or Class::ReluctantORM::Exception::SQL::TooComplex (our fault for having a weaksauce parser). |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
$options is an optional hashref that contains parsing options or hints for the parser. It may be dialect specific - see your driver subclass for details. |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=cut |
536
|
|
|
|
|
|
|
|
537
|
0
|
|
|
0
|
1
|
|
sub parse_statement { Class::ReluctantORM::Exception::Call::PureVirtual->croak(); } |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=head2 $where_obj = $driver->parse_where($where_clause_string, $options); |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
EXERIMENTAL |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
Examines the $where_clause_string, and builds a Class::ReluctantORM::SQL::Where object that semantically represents the WHERE clause. You should not include the word WHERE. |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
Other details as for parse_statement. |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=cut |
548
|
|
|
|
|
|
|
|
549
|
0
|
|
|
0
|
1
|
|
sub parse_where { Class::ReluctantORM::Exception::Call::PureVirtual->croak(); } |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=head2 $order_by_obj = $driver->parse_order_by($order_clause_string, $options); |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
EXERIMENTAL |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
Examines the $order_clause_string, and builds a Class::ReluctantORM::SQL::OrderBy object that semantically represents the clause. You should not include the words ORDER BY. |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
Other details as for parse_statement. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
A default implementation is provided. It's stupid - it only allows column names and sort directions, no expressions. |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=cut |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
sub parse_order_by { |
564
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
565
|
0
|
|
0
|
|
|
|
my $sql = shift || ''; |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
# Permit (but ignore) any ORDER BY prefix |
568
|
0
|
|
|
|
|
|
$sql =~ s/^ORDER BY\s+//i; |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
# Split on commas |
571
|
0
|
|
|
|
|
|
my @stanzas = split /\s*,\s*/, $sql; |
572
|
0
|
|
|
|
|
|
my $ob = OrderBy->new(); |
573
|
0
|
|
|
|
|
|
my %permitted = map { $_ => 1 } qw(asc ASC desc DESC); |
|
0
|
|
|
|
|
|
|
574
|
0
|
|
|
|
|
|
foreach my $stanza (@stanzas) { |
575
|
0
|
|
|
|
|
|
$stanza =~ s/^\s+//; # strip leading spaces |
576
|
0
|
|
|
|
|
|
$stanza =~ s/\s+$//; # strip trailing spaces |
577
|
0
|
|
|
|
|
|
my ($col_name, $dir) = split /\s+/, $stanza; |
578
|
0
|
0
|
0
|
|
|
|
if ($dir && !exists $permitted{$dir}) { |
579
|
0
|
|
|
|
|
|
Class::ReluctantORM::Exception::SQL::ParseError->croak( |
580
|
|
|
|
|
|
|
error => "Could not parse '$stanza' in order by clause", |
581
|
|
|
|
|
|
|
sql => $sql, |
582
|
|
|
|
|
|
|
); |
583
|
|
|
|
|
|
|
} |
584
|
0
|
|
|
|
|
|
my $col = $driver->parse_column($col_name); |
585
|
0
|
|
|
|
|
|
$ob->add($col, $dir); |
586
|
|
|
|
|
|
|
} |
587
|
0
|
|
|
|
|
|
return $ob; |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
=begin devdocs |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=head2 $col = driver->parse_column($str); |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
Parses a string token (a column name) into a Column. This is used for parsing things like "schema"."table"."column" . |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
=cut |
598
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
sub parse_column { |
600
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
601
|
0
|
|
|
|
|
|
my $str = shift; |
602
|
0
|
|
|
|
|
|
my ($oq, $cq, $ns) = |
603
|
|
|
|
|
|
|
( $driver->open_quote, $driver->close_quote, $driver->name_separator); |
604
|
|
|
|
|
|
|
|
605
|
0
|
|
|
|
|
|
my @parts = split '\\' . $ns, $str; |
606
|
0
|
|
|
|
|
|
for (@parts) { |
607
|
0
|
|
|
|
|
|
s{^$oq}{}; |
608
|
0
|
|
|
|
|
|
s{$cq$}{}; |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
|
611
|
0
|
|
|
|
|
|
my ($colname, $table, $schema) = reverse @parts; |
612
|
0
|
0
|
|
|
|
|
my $col = Column->new( |
613
|
|
|
|
|
|
|
table => ($table ? Table->new(table => $table, schema => $schema) : undef), |
614
|
|
|
|
|
|
|
column => $colname, |
615
|
|
|
|
|
|
|
); |
616
|
0
|
|
|
|
|
|
return $col; |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
} |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
#==================================================================# |
623
|
|
|
|
|
|
|
# MONITOR SUPPORT |
624
|
|
|
|
|
|
|
#==================================================================# |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=head1 MONITOR SUPPORT |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
These methods allow the Driver to integrate with the Monitor system. |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=cut |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head2 $driver->install_monitor($mon); |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
Adds a monitor to the driver. $mon should be a Class::ReluctantORM::Monitor. |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
Note that monitors may be added on a system-wide basis by calling Class::ReluctantORM::install_global_monitor(). |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=cut |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
sub install_monitor { |
641
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
642
|
0
|
|
|
|
|
|
my $mon = shift; |
643
|
0
|
0
|
|
|
|
|
unless ($mon) { Class::ReluctantORM::Exception::Param::Missing->croak(param => 'monitor'); } |
|
0
|
|
|
|
|
|
|
644
|
0
|
0
|
0
|
|
|
|
unless (blessed($mon) && $mon->isa('Class::ReluctantORM::Monitor')) { |
645
|
0
|
|
|
|
|
|
Class::ReluctantORM::Exception::Param::WrongType->croak(param => 'monitor', expected => 'Class::ReluctantORM::Monitor', value => $mon); |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
0
|
|
|
|
|
|
push @{$driver->{monitors}}, $mon; |
|
0
|
|
|
|
|
|
|
649
|
0
|
|
|
|
|
|
return 1; |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
=head2 $driver->monitors(); |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
Returns the list of monitors for this driver. The list includes monitors specific to this driver, as well as global monitors. |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
=cut |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
sub monitors { |
659
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
660
|
|
|
|
|
|
|
return ( |
661
|
0
|
|
|
|
|
|
@{$driver->{monitors}}, |
|
0
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
Class::ReluctantORM->global_monitors(), |
663
|
|
|
|
|
|
|
); |
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=head2 $driver->driver_monitors(); |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
Returns the list of monitors for this driver, excluding global monitors. |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
=cut |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
sub driver_monitors { |
673
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
674
|
0
|
|
|
|
|
|
return @{$driver->{monitors}}, |
|
0
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
} |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=head2 $driver->remove_driver_monitors(); |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
Removes all monitors on this driver. Global monitors are not affected. |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=cut |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
sub remove_driver_monitors { |
684
|
0
|
|
|
0
|
1
|
|
my $driver = shift; |
685
|
0
|
|
|
|
|
|
$driver->{monitors} = []; |
686
|
|
|
|
|
|
|
} |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=head1 MONITORING EVENT METHODS |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
Driver implementations should call these methods at the appropriate time as they work. |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
All methods take named parameters. Each method lists its required arguments. The arguments are as follows: |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=over |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
=item sql_obj |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
The Class::ReluctantORM::SQL object being rendered. |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=item sql_str |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
The rendered SQL string, ready for a prepare(). This will be in the driver's dialect. |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=item sth |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
The DBI statement handle. |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=item binds |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
An arrayref of arguments to DBI execute(). |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=item row |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
A hashref of data returned by a single row, as returned by $sth->fetchrow_hashref |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
=back |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=cut |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
=head2 $d->_monitor_render_begin(sql_obj => $so); |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
Notifies the monitoring system that the driver has begun work to render the given SQL object. |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
Arguments: sql_obj, original, untouched Class::ReluctantORM::SQL object. |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=cut |
727
|
|
|
|
|
|
|
|
728
|
0
|
|
|
0
|
|
|
sub _monitor_render_begin { __notify_monitors(@_, event => 'render_begin'); } |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=head2 $d->_monitor_render_transform(sql_obj => $so); |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
Notifies the monitoring system that the driver has finished transforming the SQL object. |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
Arguments: sql_obj, the post-transformation Class::ReluctantORM::SQL object. |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
=cut |
737
|
|
|
|
|
|
|
|
738
|
0
|
|
|
0
|
|
|
sub _monitor_render_transform { __notify_monitors(@_, event => 'render_transform'); } |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
=head2 $d->_monitor_render_finish(sql_obj => $so, sql_str => $ss); |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
Notifies the monitoring system that the driver has finished rendering the SQL object. |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
=cut |
745
|
|
|
|
|
|
|
|
746
|
0
|
|
|
0
|
|
|
sub _monitor_render_finish { __notify_monitors(@_, event => 'render_finish'); } |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
=head2 $d->_monitor_execute_begin(sql_obj => $so, sql_str => $ss, sth =>$sth, binds => \@binds); |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
Notifies the monitoring system that the driver is about to perform a DBI execute. |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
=cut |
753
|
|
|
|
|
|
|
|
754
|
0
|
|
|
0
|
|
|
sub _monitor_execute_begin { __notify_monitors(@_, event => 'execute_begin'); } |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=head2 $d->_monitor_execute_finish(sql_obj => $so, sql_str => $ss, sth =>$sth, binds => \@binds); |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
Notifies the monitoring system that the driver has returned from performing a DBI execute. |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
=cut |
761
|
|
|
|
|
|
|
|
762
|
0
|
|
|
0
|
|
|
sub _monitor_execute_finish { __notify_monitors(@_, event => 'execute_finish'); } |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
=head2 $d->_monitor_fetch_row(sql_obj => $so, sql_str => $ss, sth =>$sth, binds => \@binds, row => \%row); |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
Notifies the monitoring system that the driver has returned from performing a DBI fetchrow. |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=cut |
769
|
|
|
|
|
|
|
|
770
|
0
|
|
|
0
|
|
|
sub _monitor_fetch_row { __notify_monitors(@_, event => 'fetch_row'); } |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
=head2 $d->_monitor_finish(sql_obj => $so, sql_str => $ss, sth => $sth); |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
Notifies the monitoring system that the driver has finished the query. |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
=cut |
777
|
|
|
|
|
|
|
|
778
|
0
|
|
|
0
|
|
|
sub _monitor_finish { __notify_monitors(@_, event => 'finish'); } |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
sub __notify_monitors { |
781
|
0
|
|
|
0
|
|
|
my $driver = shift; |
782
|
0
|
|
|
|
|
|
my %args = @_; |
783
|
0
|
|
|
|
|
|
$args{driver} = $driver; |
784
|
0
|
|
|
|
|
|
my $event = $args{event}; |
785
|
0
|
|
|
|
|
|
delete $args{event}; |
786
|
0
|
|
|
|
|
|
$event = 'notify_' . $event; |
787
|
|
|
|
|
|
|
|
788
|
0
|
|
|
|
|
|
foreach my $monitor ($driver->monitors) { |
789
|
0
|
|
|
|
|
|
$monitor->$event(%args); |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
|
792
|
0
|
|
|
|
|
|
return 1; |
793
|
|
|
|
|
|
|
} |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
1; |