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 Carp::Clan qw/^DBIx::Class/; |
9 | use List::Util(); |
10 | use Scalar::Util (); |
c1cac633 |
11 | |
7b1b2582 |
12 | __PACKAGE__->mk_group_accessors(simple => qw/ |
13 | _using_dynamic_cursors |
14 | /); |
c1cac633 |
15 | |
16 | =head1 NAME |
17 | |
a89c6fc0 |
18 | DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server - Support specific |
19 | to Microsoft SQL Server over ODBC |
c1cac633 |
20 | |
21 | =head1 DESCRIPTION |
22 | |
5a77aa8b |
23 | This class implements support specific to Microsoft SQL Server over ODBC. It is |
24 | loaded automatically by by DBIx::Class::Storage::DBI::ODBC when it detects a |
25 | MSSQL back-end. |
c1cac633 |
26 | |
5a77aa8b |
27 | Most of the functionality is provided from the superclass |
28 | L<DBIx::Class::Storage::DBI::MSSQL>. |
c1cac633 |
29 | |
7b1b2582 |
30 | =head1 MULTIPLE ACTIVE STATEMENTS |
31 | |
32 | The following options are alternative ways to enable concurrent executing |
33 | statement support. Each has its own advantages and drawbacks. |
34 | |
35 | =head2 connect_call_use_dynamic_cursors |
36 | |
37 | Use as: |
38 | |
39 | on_connect_call => 'use_dynamic_cursors' |
40 | |
41 | in your L<DBIx::Class::Storage::DBI/connect_info> as one way to enable multiple |
42 | concurrent statements. |
43 | |
44 | Will add C<< odbc_cursortype => 2 >> to your DBI connection attributes. See |
45 | L<DBD::ODBC/odbc_cursortype> for more information. |
46 | |
47 | Alternatively, you can add it yourself and dynamic cursor will be automatically |
48 | enabled. |
49 | |
50 | This will not work with CODE ref connect_info's and will do nothing if you set |
51 | C<odbc_cursortype> yourself. |
52 | |
53 | B<WARNING:> this will break C<SCOPE_IDENTITY()>, and C<SELECT @@IDENTITY> will |
54 | be used instead, which on SQL Server 2005 and later will return erroneous |
55 | results on tables which have an on insert trigger that inserts into another |
56 | table with an C<IDENTITY> column. |
57 | |
58 | =cut |
59 | |
60 | sub connect_call_use_dynamic_cursors { |
61 | my $self = shift; |
62 | |
63 | if (ref($self->_dbi_connect_info->[0]) eq 'CODE') { |
64 | croak 'cannot set DBI attributes on a CODE ref connect_info'; |
65 | } |
66 | |
67 | my $dbi_attrs = $self->_dbi_connect_info->[-1]; |
68 | |
69 | unless (ref($dbi_attrs) && Scalar::Util::reftype($dbi_attrs) eq 'HASH') { |
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; |
77 | my $connected = defined $self->_dbh; |
78 | $self->disconnect; |
79 | $self->ensure_connected if $connected; |
80 | $self->_set_dynamic_cursors; |
81 | } |
82 | } |
83 | |
84 | sub _set_dynamic_cursors { |
85 | my $self = shift; |
86 | $self->_using_dynamic_cursors(1); |
87 | $self->_identity_method('@@identity'); |
88 | } |
89 | |
90 | sub _rebless { |
91 | no warnings 'uninitialized'; |
92 | my $self = shift; |
93 | |
94 | if (ref($self->_dbi_connect_info->[0]) ne 'CODE' && |
95 | eval { $self->_dbi_connect_info->[-1]{odbc_cursortype} } == 2) { |
96 | $self->_set_dynamic_cursors; |
97 | return; |
98 | } |
99 | |
100 | $self->_using_dynamic_cursors(0); |
101 | } |
102 | |
103 | =head2 connect_call_use_server_cursors |
104 | |
105 | Use as: |
106 | |
107 | on_connect_call => 'use_server_cursors' |
108 | |
109 | May allow multiple active select statements. See |
110 | L<DBD::ODBC/odbc_SQL_ROWSET_SIZE> for more information. |
111 | |
112 | Takes an optional parameter for the value to set the attribute to, default is |
113 | C<2>. |
114 | |
115 | B<WARNING>: this does not work on all versions of SQL Server, and may lock up |
116 | your database! |
117 | |
118 | =cut |
119 | |
120 | sub connect_call_use_server_cursors { |
121 | my $self = shift; |
122 | my $sql_rowset_size = shift || 2; |
123 | |
124 | $self->_dbh->{odbc_SQL_ROWSET_SIZE} = $sql_rowset_size; |
125 | } |
126 | |
127 | =head2 connect_call_use_mars |
128 | |
129 | Use as: |
130 | |
131 | on_connect_call => 'use_mars' |
132 | |
133 | Use to enable a feature of SQL Server 2005 and later, "Multiple Active Result |
134 | Sets". See L<DBD::ODBC::FAQ/Does DBD::ODBC support Multiple Active Statements?> |
135 | for more information. |
136 | |
137 | B<WARNING>: This has implications for the way transactions are handled. |
138 | |
139 | =cut |
140 | |
141 | sub connect_call_use_mars { |
142 | my $self = shift; |
143 | |
144 | my $dsn = $self->_dbi_connect_info->[0]; |
145 | |
146 | if (ref($dsn) eq 'CODE') { |
147 | croak 'cannot change the DBI DSN on a CODE ref connect_info'; |
148 | } |
149 | |
150 | if ($dsn !~ /MARS_Connection=/) { |
151 | $self->_dbi_connect_info->[0] = "$dsn;MARS_Connection=Yes"; |
152 | my $connected = defined $self->_dbh; |
153 | $self->disconnect; |
154 | $self->ensure_connected if $connected; |
155 | } |
156 | } |
157 | |
158 | 1; |
159 | |
5a77aa8b |
160 | =head1 AUTHOR |
c1cac633 |
161 | |
5a77aa8b |
162 | See L<DBIx::Class/CONTRIBUTORS>. |
c1cac633 |
163 | |
164 | =head1 LICENSE |
165 | |
166 | You may distribute this code under the same terms as Perl itself. |
167 | |
168 | =cut |
259c0e40 |
169 | # vim: sw=2 sts=2 |