merge in some more MSSQL code, including odbc dynamic cursor support
[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 Carp::Clan qw/^DBIx::Class/;
9use List::Util();
10use Scalar::Util ();
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
41in your L<DBIx::Class::Storage::DBI/connect_info> as one way to enable multiple
42concurrent statements.
43
44Will add C<< odbc_cursortype => 2 >> to your DBI connection attributes. See
45L<DBD::ODBC/odbc_cursortype> for more information.
46
47Alternatively, you can add it yourself and dynamic cursor will be automatically
48enabled.
49
50This will not work with CODE ref connect_info's and will do nothing if you set
51C<odbc_cursortype> yourself.
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') {
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
84sub _set_dynamic_cursors {
85 my $self = shift;
86 $self->_using_dynamic_cursors(1);
87 $self->_identity_method('@@identity');
88}
89
90sub _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
105Use as:
106
107 on_connect_call => 'use_server_cursors'
108
109May allow multiple active select statements. See
110L<DBD::ODBC/odbc_SQL_ROWSET_SIZE> for more information.
111
112Takes an optional parameter for the value to set the attribute to, default is
113C<2>.
114
115B<WARNING>: this does not work on all versions of SQL Server, and may lock up
116your database!
117
118=cut
119
120sub 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
129Use as:
130
131 on_connect_call => 'use_mars'
132
133Use to enable a feature of SQL Server 2005 and later, "Multiple Active Result
134Sets". See L<DBD::ODBC::FAQ/Does DBD::ODBC support Multiple Active Statements?>
135for more information.
136
137B<WARNING>: This has implications for the way transactions are handled.
138
139=cut
140
141sub 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
1581;
159
5a77aa8b 160=head1 AUTHOR
c1cac633 161
5a77aa8b 162See L<DBIx::Class/CONTRIBUTORS>.
c1cac633 163
164=head1 LICENSE
165
166You may distribute this code under the same terms as Perl itself.
167
168=cut
259c0e40 169# vim: sw=2 sts=2