File Coverage

blib/lib/DBIx/Class/Storage/DBI/mysql.pm
Criterion Covered Total %
statement 26 53 49.0
branch 9 16 56.2
condition 3 17 17.6
subroutine 6 16 37.5
pod 6 7 85.7
total 50 109 45.8


line stmt bran cond sub pod time code
1             package DBIx::Class::Storage::DBI::mysql;
2              
3 4     4   2041 use strict;
  4         9  
  4         99  
4 4     4   21 use warnings;
  4         7  
  4         93  
5              
6 4     4   18 use base qw/DBIx::Class::Storage::DBI/;
  4         7  
  4         2964  
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 0     0 1 0 my ($self, $sub) = @_;
16              
17 0         0 $self->_do_query('SET FOREIGN_KEY_CHECKS = 0');
18 0         0 $sub->();
19 0         0 $self->_do_query('SET FOREIGN_KEY_CHECKS = 1');
20             }
21              
22             sub connect_call_set_strict_mode {
23 0     0 0 0 my $self = shift;
24              
25             # the @@sql_mode puts back what was previously set on the session handle
26 0         0 $self->_do_query(q|SET SQL_MODE = CONCAT('ANSI,TRADITIONAL,ONLY_FULL_GROUP_BY,', @@sql_mode)|);
27 0         0 $self->_do_query(q|SET SQL_AUTO_IS_NULL = 0|);
28             }
29              
30             sub _dbh_last_insert_id {
31 0     0   0 my ($self, $dbh, $source, $col) = @_;
32 0         0 $dbh->{mysql_insertid};
33             }
34              
35             sub _prep_for_execute {
36 4     4   8 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 4 50 33     20 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 4         11 my $sm = $self->sql_maker;
61              
62 4         19 my $target_name = $_[1]->from;
63              
64 4 100       10 if (ref $target_name) {
65 2 50 33     16 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 2 50       9 $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 0         0 undef $target_name;
81             }
82             }
83              
84             local $sm->{_modification_target_referenced_re} =
85 4 50       130 qr/ (?
86             if $target_name;
87              
88 4         18 $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 3     3   5 my $self = shift;
96              
97             # default mysql_auto_reconnect to off unless explicitly set
98 3 50 33     23 if (
99             $self->_dbh->{mysql_auto_reconnect}
100             and
101             ! exists $self->_dbic_connect_attributes->{mysql_auto_reconnect}
102             ) {
103 0         0 $self->_dbh->{mysql_auto_reconnect} = 0;
104             }
105              
106 3         16 $self->next::method(@_);
107             }
108              
109             # we need to figure out what mysql version we're running
110             sub sql_maker {
111 34     34 1 144 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 34         605 my $mysql_ver = $self->_server_info->{normalized_dbms_version};
117              
118 34         141 my $sm = $self->next::method(@_);
119              
120             # mysql 3 does not understand a bare JOIN
121 34 100       124 $sm->{_default_jointype} = 'INNER' if $mysql_ver < 4;
122              
123 34         136 $sm;
124             }
125              
126             sub sqlt_type {
127 0     0 1   return 'MySQL';
128             }
129              
130             sub deployment_statements {
131 0     0 1   my $self = shift;
132 0           my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_;
133              
134 0   0       $sqltargs ||= {};
135              
136 0 0 0       if (
137             ! exists $sqltargs->{producer_args}{mysql_version}
138             and
139             my $dver = $self->_server_info->{normalized_dbms_version}
140             ) {
141 0           $sqltargs->{producer_args}{mysql_version} = $dver;
142             }
143              
144 0           $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
145             }
146              
147             sub _exec_svp_begin {
148 0     0     my ($self, $name) = @_;
149              
150 0           $self->_dbh->do("SAVEPOINT $name");
151             }
152              
153             sub _exec_svp_release {
154 0     0     my ($self, $name) = @_;
155              
156 0           $self->_dbh->do("RELEASE SAVEPOINT $name");
157             }
158              
159             sub _exec_svp_rollback {
160 0     0     my ($self, $name) = @_;
161              
162 0           $self->_dbh->do("ROLLBACK TO SAVEPOINT $name")
163             }
164              
165             sub is_replicating {
166 0     0 1   my $status = shift->_get_dbh->selectrow_hashref('show slave status');
167 0   0       return ($status->{Slave_IO_Running} eq 'Yes') && ($status->{Slave_SQL_Running} eq 'Yes');
168             }
169              
170             sub lag_behind_master {
171 0     0 1   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,
190             like AutoIncrement column support and savepoints. Also it augments the
191             SQL maker to support the MySQL-specific C join type, which
192             you can use by specifying C<< join_type => 'straight' >> in the
193             L
194              
195              
196             It also provides a one-stop on-connect macro C 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.
216              
217             =head1 COPYRIGHT AND LICENSE
218              
219             This module is free software L
220             by the L. You can
221             redistribute it and/or modify it under the same terms as the
222             L.