All expected evals converted to try, except where no test is done,
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / ODBC / Microsoft_SQL_Server.pm
CommitLineData
c1cac633 1package DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server;
2use strict;
3use warnings;
4
eb0323df 5use base qw/DBIx::Class::Storage::DBI::MSSQL/;
2ad62d97 6use mro 'c3';
7
7b1b2582 8use List::Util();
9use Scalar::Util ();
ed7ab0f4 10use Try::Tiny;
c1cac633 11
7b1b2582 12__PACKAGE__->mk_group_accessors(simple => qw/
13 _using_dynamic_cursors
14/);
c1cac633 15
16=head1 NAME
17
a89c6fc0 18DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server - Support specific
19to Microsoft SQL Server over ODBC
c1cac633 20
21=head1 DESCRIPTION
22
5a77aa8b 23This class implements support specific to Microsoft SQL Server over ODBC. It is
24loaded automatically by by DBIx::Class::Storage::DBI::ODBC when it detects a
25MSSQL back-end.
c1cac633 26
5a77aa8b 27Most of the functionality is provided from the superclass
28L<DBIx::Class::Storage::DBI::MSSQL>.
c1cac633 29
7b1b2582 30=head1 MULTIPLE ACTIVE STATEMENTS
31
32The following options are alternative ways to enable concurrent executing
33statement support. Each has its own advantages and drawbacks.
34
35=head2 connect_call_use_dynamic_cursors
36
37Use as:
38
39 on_connect_call => 'use_dynamic_cursors'
40
8384a713 41in your L<connect_info|DBIx::Class::Storage::DBI/connect_info> as one way to enable multiple
7b1b2582 42concurrent statements.
43
44Will add C<< odbc_cursortype => 2 >> to your DBI connection attributes. See
45L<DBD::ODBC/odbc_cursortype> for more information.
46
41dd5d30 47Alternatively, you can add it yourself and dynamic cursor support will be
48automatically enabled.
7b1b2582 49
41dd5d30 50If you're using FreeTDS, C<tds_version> must be set to at least C<8.0>.
51
52This will not work with CODE ref connect_info's.
7b1b2582 53
54B<WARNING:> this will break C<SCOPE_IDENTITY()>, and C<SELECT @@IDENTITY> will
55be used instead, which on SQL Server 2005 and later will return erroneous
56results on tables which have an on insert trigger that inserts into another
57table with an C<IDENTITY> column.
58
59=cut
60
61sub connect_call_use_dynamic_cursors {
62 my $self = shift;
63
64 if (ref($self->_dbi_connect_info->[0]) eq 'CODE') {
0a9a9955 65 $self->throw_exception ('Cannot set DBI attributes on a CODE ref connect_info');
7b1b2582 66 }
67
68 my $dbi_attrs = $self->_dbi_connect_info->[-1];
69
70 unless (ref($dbi_attrs) && Scalar::Util::reftype($dbi_attrs) eq 'HASH') {
71 $dbi_attrs = {};
72 push @{ $self->_dbi_connect_info }, $dbi_attrs;
73 }
74
75 if (not exists $dbi_attrs->{odbc_cursortype}) {
76 # turn on support for multiple concurrent statements, unless overridden
77 $dbi_attrs->{odbc_cursortype} = 2;
75517ea9 78 $self->disconnect; # resetting dbi attrs, so have to reconnect
79 $self->ensure_connected;
7b1b2582 80 $self->_set_dynamic_cursors;
81 }
82}
83
84sub _set_dynamic_cursors {
85 my $self = shift;
cbc0e07a 86 my $dbh = $self->_get_dbh;
41dd5d30 87
ed7ab0f4 88 try {
41dd5d30 89 local $dbh->{RaiseError} = 1;
90 local $dbh->{PrintError} = 0;
91 $dbh->do('SELECT @@IDENTITY');
ed7ab0f4 92 } catch {
1a58752c 93 $self->throw_exception (<<'EOF');
41dd5d30 94
95Your drivers do not seem to support dynamic cursors (odbc_cursortype => 2),
96if you're using FreeTDS, make sure to set tds_version to 8.0 or greater.
97EOF
98 }
99
7b1b2582 100 $self->_using_dynamic_cursors(1);
101 $self->_identity_method('@@identity');
102}
103
37b17a93 104sub _init {
7b1b2582 105 my $self = shift;
106
1a58752c 107 no warnings qw/uninitialized/;
108
109 if (
110 ref($self->_dbi_connect_info->[0]) ne 'CODE'
111 &&
112 ref ($self->_dbi_connect_info->[-1]) eq 'HASH'
113 &&
114 $self->_dbi_connect_info->[-1]{odbc_cursortype} == 2
115 ) {
7b1b2582 116 $self->_set_dynamic_cursors;
117 return;
118 }
119
120 $self->_using_dynamic_cursors(0);
121}
122
123=head2 connect_call_use_server_cursors
124
125Use as:
126
127 on_connect_call => 'use_server_cursors'
128
129May allow multiple active select statements. See
130L<DBD::ODBC/odbc_SQL_ROWSET_SIZE> for more information.
131
132Takes an optional parameter for the value to set the attribute to, default is
133C<2>.
134
135B<WARNING>: this does not work on all versions of SQL Server, and may lock up
136your database!
137
138=cut
139
140sub connect_call_use_server_cursors {
141 my $self = shift;
142 my $sql_rowset_size = shift || 2;
143
9ae966b9 144 $self->_get_dbh->{odbc_SQL_ROWSET_SIZE} = $sql_rowset_size;
7b1b2582 145}
146
445e08ff 147=head2 connect_call_use_MARS
7b1b2582 148
149Use as:
150
445e08ff 151 on_connect_call => 'use_MARS'
7b1b2582 152
153Use to enable a feature of SQL Server 2005 and later, "Multiple Active Result
154Sets". See L<DBD::ODBC::FAQ/Does DBD::ODBC support Multiple Active Statements?>
155for more information.
156
157B<WARNING>: This has implications for the way transactions are handled.
158
159=cut
160
445e08ff 161sub connect_call_use_MARS {
7b1b2582 162 my $self = shift;
163
164 my $dsn = $self->_dbi_connect_info->[0];
165
166 if (ref($dsn) eq 'CODE') {
1a58752c 167 $self->throw_exception('cannot change the DBI DSN on a CODE ref connect_info');
7b1b2582 168 }
169
170 if ($dsn !~ /MARS_Connection=/) {
171 $self->_dbi_connect_info->[0] = "$dsn;MARS_Connection=Yes";
9ae966b9 172 my $was_connected = defined $self->_dbh;
7b1b2582 173 $self->disconnect;
9ae966b9 174 $self->ensure_connected if $was_connected;
7b1b2582 175 }
176}
177
1781;
179
5a77aa8b 180=head1 AUTHOR
c1cac633 181
5a77aa8b 182See L<DBIx::Class/CONTRIBUTORS>.
c1cac633 183
184=head1 LICENSE
185
186You may distribute this code under the same terms as Perl itself.
187
188=cut
259c0e40 189# vim: sw=2 sts=2