Commit | Line | Data |
843f8ecd |
1 | package DBIx::Class::Storage::DBI::mysql; |
2 | |
3 | use strict; |
4 | use warnings; |
5 | |
be64931c |
6 | use base qw/DBIx::Class::Storage::DBI/; |
843f8ecd |
7 | |
45150bc4 |
8 | use namespace::clean; |
9 | |
d5dedbd6 |
10 | __PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::MySQL'); |
6a247f33 |
11 | __PACKAGE__->sql_limit_dialect ('LimitXY'); |
2b8cc2f2 |
12 | __PACKAGE__->sql_quote_char ('`'); |
843f8ecd |
13 | |
be64931c |
14 | __PACKAGE__->_use_multicolumn_in (1); |
15 | |
e96a93df |
16 | sub with_deferred_fk_checks { |
17 | my ($self, $sub) = @_; |
18 | |
5cf7285e |
19 | $self->_do_query('SET FOREIGN_KEY_CHECKS = 0'); |
e96a93df |
20 | $sub->(); |
5cf7285e |
21 | $self->_do_query('SET FOREIGN_KEY_CHECKS = 1'); |
e96a93df |
22 | } |
23 | |
97a0a148 |
24 | sub connect_call_set_strict_mode { |
0fde80d9 |
25 | my $self = shift; |
97a0a148 |
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)|); |
0fde80d9 |
29 | $self->_do_query(q|SET SQL_AUTO_IS_NULL = 0|); |
30 | } |
31 | |
d4f16b21 |
32 | sub _dbh_last_insert_id { |
33 | my ($self, $dbh, $source, $col) = @_; |
34 | $dbh->{mysql_insertid}; |
843f8ecd |
35 | } |
36 | |
45150bc4 |
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 | |
07fadea8 |
47 | # FIXME FIXME FIXME - this is a terrible, gross, incomplete, MySQL-specific |
48 | # hack but it works rather well for the limited amount of actual use cases |
49 | # which can not be done in any other way on MySQL. This allows us to fix |
50 | # some bugs without breaking MySQL support in the process and is also |
51 | # crucial for more complex things like Shadow to be usable |
52 | # |
53 | # This code is just a pre-analyzer, working in tandem with ::SQLMaker::MySQL, |
54 | # where the possibly-set value of {_modification_target_referenced_re} is |
55 | # used to demarcate which part of the final SQL to double-wrap in a subquery. |
56 | # |
57 | # This is covered extensively by "offline" tests, so when the DQ work |
58 | # resumes, this will get flagged. Afaik there are no AST-visitor code of that |
59 | # magnitude yet (Oct 2015) within DQ, so a good exercise overall. |
45150bc4 |
60 | |
61 | # extract the source name, construct modification indicator re |
62 | my $sm = $self->sql_maker; |
63 | |
64 | my $target_name = $_[1]->from; |
65 | |
66 | if (ref $target_name) { |
67 | if ( |
68 | ref $target_name eq 'SCALAR' |
69 | and |
70 | $$target_name =~ /^ (?: |
71 | \` ( [^`]+ ) \` #` |
72 | | ( [\w\-]+ ) |
73 | ) $/x |
74 | ) { |
75 | # this is just a plain-ish name, which has been literal-ed for |
76 | # whatever reason |
d77ee505 |
77 | $target_name = (defined $1) ? $1 : $2; |
45150bc4 |
78 | } |
79 | else { |
80 | # this is something very complex, perhaps a custom result source or whatnot |
81 | # can't deal with it |
82 | undef $target_name; |
83 | } |
84 | } |
85 | |
86 | local $sm->{_modification_target_referenced_re} = |
f4fdfd69 |
87 | qr/ (?<!DELETE) [\s\)] (?: FROM | JOIN ) \s (?: \` \Q$target_name\E \` | \Q$target_name\E ) [\s\(] /xi |
45150bc4 |
88 | if $target_name; |
89 | |
90 | $self->next::method(@_); |
91 | } |
92 | |
f98120e4 |
93 | # here may seem like an odd place to override, but this is the first |
94 | # method called after we are connected *and* the driver is determined |
95 | # ($self is reblessed). See code flow in ::Storage::DBI::_populate_dbh |
96 | sub _run_connection_actions { |
97 | my $self = shift; |
98 | |
99 | # default mysql_auto_reconnect to off unless explicitly set |
100 | if ( |
101 | $self->_dbh->{mysql_auto_reconnect} |
102 | and |
103 | ! exists $self->_dbic_connect_attributes->{mysql_auto_reconnect} |
104 | ) { |
105 | $self->_dbh->{mysql_auto_reconnect} = 0; |
106 | } |
107 | |
108 | $self->next::method(@_); |
109 | } |
110 | |
d3944540 |
111 | # we need to figure out what mysql version we're running |
112 | sub sql_maker { |
113 | my $self = shift; |
114 | |
b6a469f7 |
115 | # it is critical to get the version *before* calling next::method |
116 | # otherwise the potential connect will obliterate the sql_maker |
117 | # next::method will populate in the _sql_maker accessor |
118 | my $mysql_ver = $self->_server_info->{normalized_dbms_version}; |
d3944540 |
119 | |
b6a469f7 |
120 | my $sm = $self->next::method(@_); |
121 | |
122 | # mysql 3 does not understand a bare JOIN |
123 | $sm->{_default_jointype} = 'INNER' if $mysql_ver < 4; |
d3944540 |
124 | |
b6a469f7 |
125 | $sm; |
d3944540 |
126 | } |
127 | |
e8d293df |
128 | sub sqlt_type { |
129 | return 'MySQL'; |
130 | } |
131 | |
96736321 |
132 | sub deployment_statements { |
133 | my $self = shift; |
134 | my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_; |
135 | |
136 | $sqltargs ||= {}; |
137 | |
138 | if ( |
139 | ! exists $sqltargs->{producer_args}{mysql_version} |
8273e845 |
140 | and |
96736321 |
141 | my $dver = $self->_server_info->{normalized_dbms_version} |
142 | ) { |
143 | $sqltargs->{producer_args}{mysql_version} = $dver; |
144 | } |
145 | |
146 | $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest); |
147 | } |
148 | |
90d7422f |
149 | sub _exec_svp_begin { |
eeb8cfeb |
150 | my ($self, $name) = @_; |
adb3554a |
151 | |
90d7422f |
152 | $self->_dbh->do("SAVEPOINT $name"); |
adb3554a |
153 | } |
154 | |
90d7422f |
155 | sub _exec_svp_release { |
eeb8cfeb |
156 | my ($self, $name) = @_; |
adb3554a |
157 | |
90d7422f |
158 | $self->_dbh->do("RELEASE SAVEPOINT $name"); |
adb3554a |
159 | } |
160 | |
90d7422f |
161 | sub _exec_svp_rollback { |
eeb8cfeb |
162 | my ($self, $name) = @_; |
adb3554a |
163 | |
90d7422f |
164 | $self->_dbh->do("ROLLBACK TO SAVEPOINT $name") |
adb3554a |
165 | } |
48fe9087 |
166 | |
106d5f3b |
167 | sub is_replicating { |
9ae966b9 |
168 | my $status = shift->_get_dbh->selectrow_hashref('show slave status'); |
f797e89e |
169 | return ($status->{Slave_IO_Running} eq 'Yes') && ($status->{Slave_SQL_Running} eq 'Yes'); |
106d5f3b |
170 | } |
171 | |
172 | sub lag_behind_master { |
9ae966b9 |
173 | return shift->_get_dbh->selectrow_hashref('show slave status')->{Seconds_Behind_Master}; |
106d5f3b |
174 | } |
175 | |
843f8ecd |
176 | 1; |
177 | |
75d07914 |
178 | =head1 NAME |
843f8ecd |
179 | |
c9d438ff |
180 | DBIx::Class::Storage::DBI::mysql - Storage::DBI class implementing MySQL specifics |
843f8ecd |
181 | |
182 | =head1 SYNOPSIS |
183 | |
c9d438ff |
184 | Storage::DBI autodetects the underlying MySQL database, and re-blesses the |
185 | C<$storage> object into this class. |
186 | |
a5bd5d88 |
187 | my $schema = MyApp::Schema->connect( $dsn, $user, $pass, { on_connect_call => 'set_strict_mode' } ); |
843f8ecd |
188 | |
189 | =head1 DESCRIPTION |
190 | |
b8391c87 |
191 | This class implements MySQL specific bits of L<DBIx::Class::Storage::DBI>, |
192 | like AutoIncrement column support and savepoints. Also it augments the |
193 | SQL maker to support the MySQL-specific C<STRAIGHT_JOIN> join type, which |
194 | you can use by specifying C<< join_type => 'straight' >> in the |
195 | L<relationship attributes|DBIx::Class::Relationship::Base/join_type> |
196 | |
c9d438ff |
197 | |
97a0a148 |
198 | It also provides a one-stop on-connect macro C<set_strict_mode> which sets |
199 | session variables such that MySQL behaves more predictably as far as the |
200 | SQL standard is concerned. |
0fde80d9 |
201 | |
3c01add8 |
202 | =head1 STORAGE OPTIONS |
203 | |
204 | =head2 set_strict_mode |
205 | |
206 | Enables session-wide strict options upon connecting. Equivalent to: |
207 | |
208 | ->connect ( ... , { |
209 | on_connect_do => [ |
210 | q|SET SQL_MODE = CONCAT('ANSI,TRADITIONAL,ONLY_FULL_GROUP_BY,', @@sql_mode)|, |
211 | q|SET SQL_AUTO_IS_NULL = 0|, |
212 | ] |
213 | }); |
214 | |
a2bd3796 |
215 | =head1 FURTHER QUESTIONS? |
843f8ecd |
216 | |
a2bd3796 |
217 | Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>. |
843f8ecd |
218 | |
a2bd3796 |
219 | =head1 COPYRIGHT AND LICENSE |
843f8ecd |
220 | |
a2bd3796 |
221 | This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE> |
222 | by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can |
223 | redistribute it and/or modify it under the same terms as the |
224 | L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>. |