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