Introduce GOVERNANCE document and empty RESOLUTIONS file.
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / mysql.pm
CommitLineData
843f8ecd 1package DBIx::Class::Storage::DBI::mysql;
2
3use strict;
4use warnings;
5
be64931c 6use base qw/DBIx::Class::Storage::DBI/;
843f8ecd 7
d5dedbd6 8__PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::MySQL');
6a247f33 9__PACKAGE__->sql_limit_dialect ('LimitXY');
2b8cc2f2 10__PACKAGE__->sql_quote_char ('`');
843f8ecd 11
be64931c 12__PACKAGE__->_use_multicolumn_in (1);
13
e96a93df 14sub with_deferred_fk_checks {
15 my ($self, $sub) = @_;
16
5cf7285e 17 $self->_do_query('SET FOREIGN_KEY_CHECKS = 0');
e96a93df 18 $sub->();
5cf7285e 19 $self->_do_query('SET FOREIGN_KEY_CHECKS = 1');
e96a93df 20}
21
97a0a148 22sub connect_call_set_strict_mode {
0fde80d9 23 my $self = shift;
97a0a148 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)|);
0fde80d9 27 $self->_do_query(q|SET SQL_AUTO_IS_NULL = 0|);
28}
29
d4f16b21 30sub _dbh_last_insert_id {
31 my ($self, $dbh, $source, $col) = @_;
32 $dbh->{mysql_insertid};
843f8ecd 33}
34
45150bc4 35sub _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
07fadea8 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.
45150bc4 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
d77ee505 75 $target_name = (defined $1) ? $1 : $2;
45150bc4 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} =
f4fdfd69 85 qr/ (?<!DELETE) [\s\)] (?: FROM | JOIN ) \s (?: \` \Q$target_name\E \` | \Q$target_name\E ) [\s\(] /xi
45150bc4 86 if $target_name;
87
88 $self->next::method(@_);
89}
90
f98120e4 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
94sub _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
d3944540 109# we need to figure out what mysql version we're running
110sub sql_maker {
111 my $self = shift;
112
b6a469f7 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};
d3944540 117
b6a469f7 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;
d3944540 122
b6a469f7 123 $sm;
d3944540 124}
125
e8d293df 126sub sqlt_type {
127 return 'MySQL';
128}
129
96736321 130sub 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}
8273e845 138 and
96736321 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
90d7422f 147sub _exec_svp_begin {
eeb8cfeb 148 my ($self, $name) = @_;
adb3554a 149
90d7422f 150 $self->_dbh->do("SAVEPOINT $name");
adb3554a 151}
152
90d7422f 153sub _exec_svp_release {
eeb8cfeb 154 my ($self, $name) = @_;
adb3554a 155
90d7422f 156 $self->_dbh->do("RELEASE SAVEPOINT $name");
adb3554a 157}
158
90d7422f 159sub _exec_svp_rollback {
eeb8cfeb 160 my ($self, $name) = @_;
adb3554a 161
90d7422f 162 $self->_dbh->do("ROLLBACK TO SAVEPOINT $name")
adb3554a 163}
48fe9087 164
106d5f3b 165sub is_replicating {
9ae966b9 166 my $status = shift->_get_dbh->selectrow_hashref('show slave status');
f797e89e 167 return ($status->{Slave_IO_Running} eq 'Yes') && ($status->{Slave_SQL_Running} eq 'Yes');
106d5f3b 168}
169
170sub lag_behind_master {
9ae966b9 171 return shift->_get_dbh->selectrow_hashref('show slave status')->{Seconds_Behind_Master};
106d5f3b 172}
173
843f8ecd 1741;
175
75d07914 176=head1 NAME
843f8ecd 177
c9d438ff 178DBIx::Class::Storage::DBI::mysql - Storage::DBI class implementing MySQL specifics
843f8ecd 179
180=head1 SYNOPSIS
181
c9d438ff 182Storage::DBI autodetects the underlying MySQL database, and re-blesses the
183C<$storage> object into this class.
184
a5bd5d88 185 my $schema = MyApp::Schema->connect( $dsn, $user, $pass, { on_connect_call => 'set_strict_mode' } );
843f8ecd 186
187=head1 DESCRIPTION
188
b8391c87 189This class implements MySQL specific bits of L<DBIx::Class::Storage::DBI>,
190like AutoIncrement column support and savepoints. Also it augments the
191SQL maker to support the MySQL-specific C<STRAIGHT_JOIN> join type, which
192you can use by specifying C<< join_type => 'straight' >> in the
193L<relationship attributes|DBIx::Class::Relationship::Base/join_type>
194
c9d438ff 195
97a0a148 196It also provides a one-stop on-connect macro C<set_strict_mode> which sets
197session variables such that MySQL behaves more predictably as far as the
198SQL standard is concerned.
0fde80d9 199
3c01add8 200=head1 STORAGE OPTIONS
201
202=head2 set_strict_mode
203
204Enables 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
a2bd3796 213=head1 FURTHER QUESTIONS?
843f8ecd 214
a2bd3796 215Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
843f8ecd 216
a2bd3796 217=head1 COPYRIGHT AND LICENSE
843f8ecd 218
a2bd3796 219This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
220by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
221redistribute it and/or modify it under the same terms as the
222L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.