Filename | /usr/share/perl5/DBIx/Class/Storage/DBI/mysql.pm |
Statements | Executed 0 statements in 0s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 69µs | 3.86ms | _run_connection_actions | DBIx::Class::Storage::DBI::mysql::
1 | 1 | 1 | 22µs | 35µs | BEGIN@3 | DBIx::Class::Storage::DBI::mysql::
1 | 1 | 1 | 12µs | 89µs | BEGIN@6 | DBIx::Class::Storage::DBI::mysql::
1 | 1 | 1 | 11µs | 108µs | BEGIN@8 | DBIx::Class::Storage::DBI::mysql::
1 | 1 | 1 | 11µs | 21µs | BEGIN@4 | DBIx::Class::Storage::DBI::mysql::
2 | 2 | 2 | 2µs | 2µs | debug (xsub) | DBIx::Class::Storage::DBI::mysql::
2 | 2 | 2 | 2µs | 2µs | transaction_depth (xsub) | DBIx::Class::Storage::DBI::mysql::
1 | 1 | 1 | 500ns | 500ns | on_connect_call (xsub) | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | _dbh_last_insert_id | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | _exec_svp_begin | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | _exec_svp_release | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | _exec_svp_rollback | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | _prep_for_execute | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | connect_call_set_strict_mode | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | deployment_statements | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | is_replicating | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | lag_behind_master | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | sql_maker | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | sqlt_type | DBIx::Class::Storage::DBI::mysql::
0 | 0 | 0 | 0s | 0s | with_deferred_fk_checks | DBIx::Class::Storage::DBI::mysql::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package DBIx::Class::Storage::DBI::mysql; | ||||
2 | |||||
3 | 2 | 48µs | # spent 35µs (22+13) within DBIx::Class::Storage::DBI::mysql::BEGIN@3 which was called:
# once (22µs+13µs) by Class::C3::Componentised::ensure_class_loaded at line 3 # spent 35µs making 1 call to DBIx::Class::Storage::DBI::mysql::BEGIN@3
# spent 13µs making 1 call to strict::import | ||
4 | 2 | 32µs | # spent 21µs (11+10) within DBIx::Class::Storage::DBI::mysql::BEGIN@4 which was called:
# once (11µs+10µs) by Class::C3::Componentised::ensure_class_loaded at line 4 # spent 21µs making 1 call to DBIx::Class::Storage::DBI::mysql::BEGIN@4
# spent 10µs making 1 call to warnings::import | ||
5 | |||||
6 | 2 | 166µs | # spent 89µs (12+77) within DBIx::Class::Storage::DBI::mysql::BEGIN@6 which was called:
# once (12µs+77µs) by Class::C3::Componentised::ensure_class_loaded at line 6 # spent 89µs making 1 call to DBIx::Class::Storage::DBI::mysql::BEGIN@6
# spent 77µs making 1 call to base::import | ||
7 | |||||
8 | 2 | 206µs | # spent 108µs (11+97) within DBIx::Class::Storage::DBI::mysql::BEGIN@8 which was called:
# once (11µs+97µs) by Class::C3::Componentised::ensure_class_loaded at line 8 # spent 108µs making 1 call to DBIx::Class::Storage::DBI::mysql::BEGIN@8
# spent 97µs making 1 call to namespace::clean::import | ||
9 | |||||
10 | 1 | 45µs | __PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::MySQL'); # spent 45µs making 1 call to DBIx::Class::Storage::DBI::sql_maker_class | ||
11 | 1 | 9µs | __PACKAGE__->sql_limit_dialect ('LimitXY'); # spent 9µs making 1 call to DBIx::Class::Storage::DBI::sql_limit_dialect | ||
12 | 1 | 8µs | __PACKAGE__->sql_quote_char ('`'); # spent 8µs making 1 call to DBIx::Class::Storage::DBI::sql_quote_char | ||
13 | |||||
14 | 1 | 16µs | __PACKAGE__->_use_multicolumn_in (1); # spent 16µs making 1 call to DBIx::Class::Storage::DBI::_use_multicolumn_in | ||
15 | |||||
16 | sub with_deferred_fk_checks { | ||||
17 | my ($self, $sub) = @_; | ||||
18 | |||||
19 | $self->_do_query('SET FOREIGN_KEY_CHECKS = 0'); | ||||
20 | $sub->(); | ||||
21 | $self->_do_query('SET FOREIGN_KEY_CHECKS = 1'); | ||||
22 | } | ||||
23 | |||||
24 | sub connect_call_set_strict_mode { | ||||
25 | my $self = shift; | ||||
26 | |||||
27 | # the @@sql_mode puts back what was previously set on the session handle | ||||
28 | $self->_do_query(q|SET SQL_MODE = CONCAT('ANSI,TRADITIONAL,ONLY_FULL_GROUP_BY,', @@sql_mode)|); | ||||
29 | $self->_do_query(q|SET SQL_AUTO_IS_NULL = 0|); | ||||
30 | } | ||||
31 | |||||
32 | sub _dbh_last_insert_id { | ||||
33 | my ($self, $dbh, $source, $col) = @_; | ||||
34 | $dbh->{mysql_insertid}; | ||||
35 | } | ||||
36 | |||||
37 | sub _prep_for_execute { | ||||
38 | my $self = shift; | ||||
39 | #(my $op, $ident, $args) = @_; | ||||
40 | |||||
41 | # Only update and delete need special double-subquery treatment | ||||
42 | # Insert referencing the same table (i.e. SELECT MAX(id) + 1) seems | ||||
43 | # to work just fine on MySQL | ||||
44 | return $self->next::method(@_) if ( $_[0] eq 'select' or $_[0] eq 'insert' ); | ||||
45 | |||||
46 | |||||
47 | # FIXME FIXME FIXME - this is a terrible, gross, incomplete hack | ||||
48 | # it should be trivial for mst to port this to DQ (and a good | ||||
49 | # exercise as well, since we do not yet have such wide tree walking | ||||
50 | # in place). For the time being this will work in limited cases, | ||||
51 | # mainly complex update/delete, which is really all we want it for | ||||
52 | # currently (allows us to fix some bugs without breaking MySQL in | ||||
53 | # the process, and is also crucial for Shadow to be usable) | ||||
54 | |||||
55 | # extract the source name, construct modification indicator re | ||||
56 | my $sm = $self->sql_maker; | ||||
57 | |||||
58 | my $target_name = $_[1]->from; | ||||
59 | |||||
60 | if (ref $target_name) { | ||||
61 | if ( | ||||
62 | ref $target_name eq 'SCALAR' | ||||
63 | and | ||||
64 | $$target_name =~ /^ (?: | ||||
65 | \` ( [^`]+ ) \` #` | ||||
66 | | ( [\w\-]+ ) | ||||
67 | ) $/x | ||||
68 | ) { | ||||
69 | # this is just a plain-ish name, which has been literal-ed for | ||||
70 | # whatever reason | ||||
71 | $target_name = (defined $1) ? $1 : $2; | ||||
72 | } | ||||
73 | else { | ||||
74 | # this is something very complex, perhaps a custom result source or whatnot | ||||
75 | # can't deal with it | ||||
76 | undef $target_name; | ||||
77 | } | ||||
78 | } | ||||
79 | |||||
80 | local $sm->{_modification_target_referenced_re} = | ||||
81 | qr/ (?<!DELETE) [\s\)] (?: FROM | JOIN ) \s (?: \` \Q$target_name\E \` | \Q$target_name\E ) [\s\(] /xi | ||||
82 | if $target_name; | ||||
83 | |||||
84 | $self->next::method(@_); | ||||
85 | } | ||||
86 | |||||
87 | # here may seem like an odd place to override, but this is the first | ||||
88 | # method called after we are connected *and* the driver is determined | ||||
89 | # ($self is reblessed). See code flow in ::Storage::DBI::_populate_dbh | ||||
90 | # spent 3.86ms (69µs+3.79) within DBIx::Class::Storage::DBI::mysql::_run_connection_actions which was called:
# once (69µs+3.79ms) by DBIx::Class::Storage::DBI::_populate_dbh at line 1056 of DBIx/Class/Storage/DBI.pm | ||||
91 | my $self = shift; | ||||
92 | |||||
93 | # default mysql_auto_reconnect to off unless explicitly set | ||||
94 | 5 | 17µs | if ( # spent 12µs making 1 call to DBI::common::FETCH
# spent 2µs making 1 call to DBI::common::STORE
# spent 1µs making 2 calls to DBIx::Class::Storage::DBI::_dbh, avg 600ns/call
# spent 1µs making 1 call to DBIx::Class::Storage::DBI::_dbic_connect_attributes | ||
95 | $self->_dbh->{mysql_auto_reconnect} | ||||
96 | and | ||||
97 | ! exists $self->_dbic_connect_attributes->{mysql_auto_reconnect} | ||||
98 | ) { | ||||
99 | $self->_dbh->{mysql_auto_reconnect} = 0; | ||||
100 | } | ||||
101 | |||||
102 | 1 | 9µs | $self->next::method(@_); # spent 9µs making 1 call to next::method | ||
103 | } | ||||
104 | |||||
105 | # we need to figure out what mysql version we're running | ||||
106 | sub sql_maker { | ||||
107 | my $self = shift; | ||||
108 | |||||
109 | # it is critical to get the version *before* calling next::method | ||||
110 | # otherwise the potential connect will obliterate the sql_maker | ||||
111 | # next::method will populate in the _sql_maker accessor | ||||
112 | my $mysql_ver = $self->_server_info->{normalized_dbms_version}; | ||||
113 | |||||
114 | my $sm = $self->next::method(@_); | ||||
115 | |||||
116 | # mysql 3 does not understand a bare JOIN | ||||
117 | $sm->{_default_jointype} = 'INNER' if $mysql_ver < 4; | ||||
118 | |||||
119 | $sm; | ||||
120 | } | ||||
121 | |||||
122 | sub sqlt_type { | ||||
123 | return 'MySQL'; | ||||
124 | } | ||||
125 | |||||
126 | sub deployment_statements { | ||||
127 | my $self = shift; | ||||
128 | my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_; | ||||
129 | |||||
130 | $sqltargs ||= {}; | ||||
131 | |||||
132 | if ( | ||||
133 | ! exists $sqltargs->{producer_args}{mysql_version} | ||||
134 | and | ||||
135 | my $dver = $self->_server_info->{normalized_dbms_version} | ||||
136 | ) { | ||||
137 | $sqltargs->{producer_args}{mysql_version} = $dver; | ||||
138 | } | ||||
139 | |||||
140 | $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest); | ||||
141 | } | ||||
142 | |||||
143 | sub _exec_svp_begin { | ||||
144 | my ($self, $name) = @_; | ||||
145 | |||||
146 | $self->_dbh->do("SAVEPOINT $name"); | ||||
147 | } | ||||
148 | |||||
149 | sub _exec_svp_release { | ||||
150 | my ($self, $name) = @_; | ||||
151 | |||||
152 | $self->_dbh->do("RELEASE SAVEPOINT $name"); | ||||
153 | } | ||||
154 | |||||
155 | sub _exec_svp_rollback { | ||||
156 | my ($self, $name) = @_; | ||||
157 | |||||
158 | $self->_dbh->do("ROLLBACK TO SAVEPOINT $name") | ||||
159 | } | ||||
160 | |||||
161 | sub is_replicating { | ||||
162 | my $status = shift->_get_dbh->selectrow_hashref('show slave status'); | ||||
163 | return ($status->{Slave_IO_Running} eq 'Yes') && ($status->{Slave_SQL_Running} eq 'Yes'); | ||||
164 | } | ||||
165 | |||||
166 | sub lag_behind_master { | ||||
167 | return shift->_get_dbh->selectrow_hashref('show slave status')->{Seconds_Behind_Master}; | ||||
168 | } | ||||
169 | |||||
170 | 1; | ||||
171 | |||||
172 | =head1 NAME | ||||
173 | |||||
174 | DBIx::Class::Storage::DBI::mysql - Storage::DBI class implementing MySQL specifics | ||||
175 | |||||
176 | =head1 SYNOPSIS | ||||
177 | |||||
178 | Storage::DBI autodetects the underlying MySQL database, and re-blesses the | ||||
179 | C<$storage> object into this class. | ||||
180 | |||||
181 | my $schema = MyApp::Schema->connect( $dsn, $user, $pass, { on_connect_call => 'set_strict_mode' } ); | ||||
182 | |||||
183 | =head1 DESCRIPTION | ||||
184 | |||||
185 | This class implements MySQL specific bits of L<DBIx::Class::Storage::DBI>, | ||||
186 | like AutoIncrement column support and savepoints. Also it augments the | ||||
187 | SQL maker to support the MySQL-specific C<STRAIGHT_JOIN> join type, which | ||||
188 | you can use by specifying C<< join_type => 'straight' >> in the | ||||
189 | L<relationship attributes|DBIx::Class::Relationship::Base/join_type> | ||||
190 | |||||
191 | |||||
192 | It also provides a one-stop on-connect macro C<set_strict_mode> which sets | ||||
193 | session variables such that MySQL behaves more predictably as far as the | ||||
194 | SQL standard is concerned. | ||||
195 | |||||
196 | =head1 STORAGE OPTIONS | ||||
197 | |||||
198 | =head2 set_strict_mode | ||||
199 | |||||
200 | Enables session-wide strict options upon connecting. Equivalent to: | ||||
201 | |||||
202 | ->connect ( ... , { | ||||
203 | on_connect_do => [ | ||||
204 | q|SET SQL_MODE = CONCAT('ANSI,TRADITIONAL,ONLY_FULL_GROUP_BY,', @@sql_mode)|, | ||||
205 | q|SET SQL_AUTO_IS_NULL = 0|, | ||||
206 | ] | ||||
207 | }); | ||||
208 | |||||
209 | =head1 FURTHER QUESTIONS? | ||||
210 | |||||
211 | Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>. | ||||
212 | |||||
213 | =head1 COPYRIGHT AND LICENSE | ||||
214 | |||||
215 | This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE> | ||||
216 | by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can | ||||
217 | redistribute it and/or modify it under the same terms as the | ||||
218 | 1 | 31µs | L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>. # spent 31µs making 1 call to B::Hooks::EndOfScope::XS::__ANON__ | ||
# spent 2µs within DBIx::Class::Storage::DBI::mysql::debug which was called 2 times, avg 1µs/call:
# once (1µs+0s) by DBIx::Class::Storage::DBI::_query_start at line 913 of Class/Accessor/Grouped.pm
# once (1µs+0s) by DBIx::Class::Storage::DBI::_query_end at line 1771 of DBIx/Class/Storage/DBI.pm | |||||
# spent 500ns within DBIx::Class::Storage::DBI::mysql::on_connect_call which was called:
# once (500ns+0s) by DBIx::Class::Storage::DBI::mysql::_run_connection_actions at line 913 of Class/Accessor/Grouped.pm | |||||
# spent 2µs within DBIx::Class::Storage::DBI::mysql::transaction_depth which was called 2 times, avg 900ns/call:
# once (1µs+0s) by DBIx::Class::Storage::BlockRunner::__ANON__[/usr/share/perl5/DBIx/Class/Storage/BlockRunner.pm:233] at line 159 of DBIx/Class/Storage/BlockRunner.pm
# once (400ns+0s) by DBIx::Class::Storage::DBI::dbh_do at line 913 of Class/Accessor/Grouped.pm |