Comments on code
[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
26d54a1d 8use Try::Tiny;
9use namespace::clean;
10
d5dedbd6 11__PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::MySQL');
6a247f33 12__PACKAGE__->sql_limit_dialect ('LimitXY');
2b8cc2f2 13__PACKAGE__->sql_quote_char ('`');
843f8ecd 14
be64931c 15__PACKAGE__->_use_multicolumn_in (1);
16
26d54a1d 17# We turn FOREIGN_KEY_CHECKS off, do a transaction, then turn them back on right
18# before the COMMIT so that they can be checked during the COMMIT.
19
c0992bf1 20# nothing tests this hypothesis, why?
21
e96a93df 22sub with_deferred_fk_checks {
23 my ($self, $sub) = @_;
24
5cf7285e 25 $self->_do_query('SET FOREIGN_KEY_CHECKS = 0');
26d54a1d 26
27 my $tried_fk_checks_reset = 0;
28
29 return try {
30 my $guard = $self->txn_scope_guard;
31 preserve_context { $sub->() } after => sub {
32 $tried_fk_checks_reset = 1;
33 $self->_do_query('SET FOREIGN_KEY_CHECKS = 1');
34 $guard->commit;
35 };
36 }
37 catch {
38 my $e = $_;
39 if (not $tried_fk_checks_reset) {
40 eval {
41 $self->_do_query('SET FOREIGN_KEY_CHECKS = 1');
42 };
43 if ($@) {
44 $e .= " also 'SET FOREIGN_KEY_CHECKS = 1' failed: $@"
45 }
46 }
47 $self->throw_exception($e);
48 };
e96a93df 49}
50
97a0a148 51sub connect_call_set_strict_mode {
0fde80d9 52 my $self = shift;
97a0a148 53
54 # the @@sql_mode puts back what was previously set on the session handle
55 $self->_do_query(q|SET SQL_MODE = CONCAT('ANSI,TRADITIONAL,ONLY_FULL_GROUP_BY,', @@sql_mode)|);
0fde80d9 56 $self->_do_query(q|SET SQL_AUTO_IS_NULL = 0|);
57}
58
d4f16b21 59sub _dbh_last_insert_id {
60 my ($self, $dbh, $source, $col) = @_;
61 $dbh->{mysql_insertid};
843f8ecd 62}
63
f98120e4 64# here may seem like an odd place to override, but this is the first
65# method called after we are connected *and* the driver is determined
66# ($self is reblessed). See code flow in ::Storage::DBI::_populate_dbh
67sub _run_connection_actions {
68 my $self = shift;
69
70 # default mysql_auto_reconnect to off unless explicitly set
71 if (
72 $self->_dbh->{mysql_auto_reconnect}
73 and
74 ! exists $self->_dbic_connect_attributes->{mysql_auto_reconnect}
75 ) {
76 $self->_dbh->{mysql_auto_reconnect} = 0;
77 }
78
79 $self->next::method(@_);
80}
81
d3944540 82# we need to figure out what mysql version we're running
83sub sql_maker {
84 my $self = shift;
85
86 unless ($self->_sql_maker) {
87 my $maker = $self->next::method (@_);
88
89 # mysql 3 does not understand a bare JOIN
af1f4f84 90 my $mysql_ver = $self->_dbh_get_info('SQL_DBMS_VER');
d3944540 91 $maker->{_default_jointype} = 'INNER' if $mysql_ver =~ /^3/;
92 }
93
94 return $self->_sql_maker;
95}
96
e8d293df 97sub sqlt_type {
98 return 'MySQL';
99}
100
96736321 101sub deployment_statements {
102 my $self = shift;
103 my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_;
104
105 $sqltargs ||= {};
106
107 if (
108 ! exists $sqltargs->{producer_args}{mysql_version}
8273e845 109 and
96736321 110 my $dver = $self->_server_info->{normalized_dbms_version}
111 ) {
112 $sqltargs->{producer_args}{mysql_version} = $dver;
113 }
114
115 $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
116}
117
90d7422f 118sub _exec_svp_begin {
eeb8cfeb 119 my ($self, $name) = @_;
adb3554a 120
90d7422f 121 $self->_dbh->do("SAVEPOINT $name");
adb3554a 122}
123
90d7422f 124sub _exec_svp_release {
eeb8cfeb 125 my ($self, $name) = @_;
adb3554a 126
90d7422f 127 $self->_dbh->do("RELEASE SAVEPOINT $name");
adb3554a 128}
129
90d7422f 130sub _exec_svp_rollback {
eeb8cfeb 131 my ($self, $name) = @_;
adb3554a 132
90d7422f 133 $self->_dbh->do("ROLLBACK TO SAVEPOINT $name")
adb3554a 134}
48fe9087 135
106d5f3b 136sub is_replicating {
9ae966b9 137 my $status = shift->_get_dbh->selectrow_hashref('show slave status');
f797e89e 138 return ($status->{Slave_IO_Running} eq 'Yes') && ($status->{Slave_SQL_Running} eq 'Yes');
106d5f3b 139}
140
141sub lag_behind_master {
9ae966b9 142 return shift->_get_dbh->selectrow_hashref('show slave status')->{Seconds_Behind_Master};
106d5f3b 143}
144
843f8ecd 1451;
146
75d07914 147=head1 NAME
843f8ecd 148
c9d438ff 149DBIx::Class::Storage::DBI::mysql - Storage::DBI class implementing MySQL specifics
843f8ecd 150
151=head1 SYNOPSIS
152
c9d438ff 153Storage::DBI autodetects the underlying MySQL database, and re-blesses the
154C<$storage> object into this class.
155
3ce9dd08 156 my $schema = MyDb::Schema->connect( $dsn, $user, $pass, { on_connect_call => 'set_strict_mode' } );
843f8ecd 157
158=head1 DESCRIPTION
159
b8391c87 160This class implements MySQL specific bits of L<DBIx::Class::Storage::DBI>,
161like AutoIncrement column support and savepoints. Also it augments the
162SQL maker to support the MySQL-specific C<STRAIGHT_JOIN> join type, which
163you can use by specifying C<< join_type => 'straight' >> in the
164L<relationship attributes|DBIx::Class::Relationship::Base/join_type>
165
c9d438ff 166
97a0a148 167It also provides a one-stop on-connect macro C<set_strict_mode> which sets
168session variables such that MySQL behaves more predictably as far as the
169SQL standard is concerned.
0fde80d9 170
3c01add8 171=head1 STORAGE OPTIONS
172
173=head2 set_strict_mode
174
175Enables session-wide strict options upon connecting. Equivalent to:
176
177 ->connect ( ... , {
178 on_connect_do => [
179 q|SET SQL_MODE = CONCAT('ANSI,TRADITIONAL,ONLY_FULL_GROUP_BY,', @@sql_mode)|,
180 q|SET SQL_AUTO_IS_NULL = 0|,
181 ]
182 });
183
843f8ecd 184=head1 AUTHORS
185
c9d438ff 186See L<DBIx::Class/CONTRIBUTORS>
843f8ecd 187
188=head1 LICENSE
189
190You may distribute this code under the same terms as Perl itself.
191
192=cut