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