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