Remove use of Try::Tiny entirely (the missing part of ddcc02d1)
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / MSSQL.pm
CommitLineData
75d07914 1package DBIx::Class::Storage::DBI::MSSQL;
3885cff6 2
75d07914 3use strict;
4use warnings;
3885cff6 5
fabbd5cc 6use base qw/
7 DBIx::Class::Storage::DBI::UniqueIdentifier
8 DBIx::Class::Storage::DBI::IdentityInsert
9/;
2ad62d97 10use mro 'c3';
fabbd5cc 11
e2741c7f 12use DBIx::Class::_Util qw( dbic_internal_try dbic_internal_catch sigwarn_silencer );
fd323bf1 13use namespace::clean;
3885cff6 14
7b1b2582 15__PACKAGE__->mk_group_accessors(simple => qw/
25d3127d 16 _identity _identity_method _no_scope_identity_query
7b1b2582 17/);
18
d5dedbd6 19__PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::MSSQL');
ac93965c 20
2b8cc2f2 21__PACKAGE__->sql_quote_char([qw/[ ]/]);
22
6f7a118e 23__PACKAGE__->datetime_parser_type (
24 'DBIx::Class::Storage::DBI::MSSQL::DateTime::Format'
25);
26
40d8d018 27__PACKAGE__->new_guid('NEWID()');
28
5a77aa8b 29sub _prep_for_execute {
30 my $self = shift;
0e773352 31 my ($op, $ident, $args) = @_;
5a77aa8b 32
33# cast MONEY values properly
34 if ($op eq 'insert' || $op eq 'update') {
35 my $fields = $args->[0];
5a77aa8b 36
52416317 37 my $colinfo = $ident->columns_info([keys %$fields]);
38
5a77aa8b 39 for my $col (keys %$fields) {
1537084d 40 # $ident is a result source object with INSERT/UPDATE ops
52416317 41 if (
42 $colinfo->{$col}{data_type}
43 &&
44 $colinfo->{$col}{data_type} =~ /^money\z/i
45 ) {
5a77aa8b 46 my $val = $fields->{$col};
47 $fields->{$col} = \['CAST(? AS MONEY)', [ $col => $val ]];
48 }
49 }
50 }
51
52 my ($sql, $bind) = $self->next::method (@_);
53
fabbd5cc 54 # SELECT SCOPE_IDENTITY only works within a statement scope. We
4a0eed52 55 # must try to always use this particular idiom first, as it is the
fabbd5cc 56 # only one that guarantees retrieving the correct id under high
57 # concurrency. When this fails we will fall back to whatever secondary
58 # retrieval method is specified in _identity_method, but at this
59 # point we don't have many guarantees we will get what we expected.
60 # http://msdn.microsoft.com/en-us/library/ms190315.aspx
61 # http://davidhayden.com/blog/dave/archive/2006/01/17/2736.aspx
25d3127d 62 if ($self->_perform_autoinc_retrieval and not $self->_no_scope_identity_query) {
384b8bce 63 $sql .= "\nSELECT SCOPE_IDENTITY()";
5a77aa8b 64 }
65
66 return ($sql, $bind);
67}
68
69sub _execute {
70 my $self = shift;
5a77aa8b 71
fabbd5cc 72 # always list ctx - we need the $sth
0e773352 73 my ($rv, $sth, @bind) = $self->next::method(@_);
1537084d 74
fabbd5cc 75 if ($self->_perform_autoinc_retrieval) {
5a77aa8b 76
25d3127d 77 # attempt to bring back the result of SELECT SCOPE_IDENTITY() we tacked
1537084d 78 # on in _prep_for_execute above
25d3127d 79 my $identity;
80
81 # we didn't even try on ftds
82 unless ($self->_no_scope_identity_query) {
ddcc02d1 83 ($identity) = dbic_internal_try { $sth->fetchrow_array };
25d3127d 84 $sth->finish;
85 }
ed8de058 86
1537084d 87 # SCOPE_IDENTITY failed, but we can do something else
88 if ( (! $identity) && $self->_identity_method) {
89 ($identity) = $self->_dbh->selectrow_array(
90 'select ' . $self->_identity_method
91 );
92 }
7b1b2582 93
1537084d 94 $self->_identity($identity);
7b1b2582 95 }
96
1537084d 97 return wantarray ? ($rv, $sth, @bind) : $rv;
7b1b2582 98}
5a77aa8b 99
7b1b2582 100sub last_insert_id { shift->_identity }
5a77aa8b 101
f0bd60fc 102#
e74c68ce 103# MSSQL is retarded wrt ordered subselects. One needs to add a TOP
6a247f33 104# to *all* subqueries, but one also *can't* use TOP 100 PERCENT
e74c68ce 105# http://sqladvice.com/forums/permalink/18496/22931/ShowThread.aspx#22931
f0bd60fc 106#
107sub _select_args_to_query {
b928a9d5 108 #my ($self, $ident, $select, $cond, $attrs) = @_;
f0bd60fc 109 my $self = shift;
b928a9d5 110 my $attrs = $_[3];
f0bd60fc 111
b928a9d5 112 my $sql_bind = $self->next::method (@_);
f0bd60fc 113
b8d88d9b 114 # see if this is an ordered subquery
aca481d8 115 if (
b928a9d5 116 $$sql_bind->[0] !~ /^ \s* \( \s* SELECT \s+ TOP \s+ \d+ \s+ /xi
117 and
bac358c9 118 scalar $self->_extract_order_criteria ($attrs->{order_by})
aca481d8 119 ) {
6de07ea3 120 $self->throw_exception(
e705f529 121 'An ordered subselect encountered - this is not safe! Please see "Ordered Subselects" in DBIx::Class::Storage::DBI::MSSQL'
122 ) unless $attrs->{unsafe_subselect_ok};
b928a9d5 123
124 $$sql_bind->[0] =~ s/^ \s* \( \s* SELECT (?=\s) / '(SELECT TOP ' . $self->sql_maker->__max_int /exi;
f0bd60fc 125 }
126
b928a9d5 127 $sql_bind;
f0bd60fc 128}
129
130
4c0f4206 131# savepoint syntax is the same as in Sybase ASE
132
90d7422f 133sub _exec_svp_begin {
4c0f4206 134 my ($self, $name) = @_;
135
90d7422f 136 $self->_dbh->do("SAVE TRANSACTION $name");
4c0f4206 137}
138
139# A new SAVE TRANSACTION with the same name releases the previous one.
90d7422f 140sub _exec_svp_release { 1 }
4c0f4206 141
90d7422f 142sub _exec_svp_rollback {
4c0f4206 143 my ($self, $name) = @_;
144
90d7422f 145 $self->_dbh->do("ROLLBACK TRANSACTION $name");
4c0f4206 146}
147
eb0323df 148sub sqlt_type { 'SQLServer' }
149
6a247f33 150sub sql_limit_dialect {
50772633 151 my $self = shift;
eb0323df 152
6a247f33 153 my $supports_rno = 0;
ff153e24 154
6a247f33 155 if (exists $self->_server_info->{normalized_dbms_version}) {
156 $supports_rno = 1 if $self->_server_info->{normalized_dbms_version} >= 9;
157 }
158 else {
159 # User is connecting via DBD::Sybase and has no permission to run
160 # stored procedures like xp_msver, or version detection failed for some
161 # other reason.
162 # So, we use a query to check if RNO is implemented.
ddcc02d1 163 dbic_internal_try {
6a247f33 164 $self->_get_dbh->selectrow_array('SELECT row_number() OVER (ORDER BY rand())');
165 $supports_rno = 1;
166 };
50772633 167 }
e76e7b5c 168
6a247f33 169 return $supports_rno ? 'RowNumberOver' : 'Top';
ed8de058 170}
3885cff6 171
ecdf1ac8 172sub _ping {
173 my $self = shift;
174
175 my $dbh = $self->_dbh or return 0;
176
d3a2e424 177 dbic_internal_try {
178 local $dbh->{RaiseError} = 1;
179 local $dbh->{PrintError} = 0;
ecdf1ac8 180
ecdf1ac8 181 $dbh->do('select 1');
52b420dd 182 1;
d3a2e424 183 }
e2741c7f 184 dbic_internal_catch {
d3a2e424 185 # MSSQL is *really* annoying wrt multiple active resultsets,
186 # and this may very well be the reason why the _ping failed
187 #
188 # Proactively disconnect, while hiding annoying warnings if the case
189 #
190 # The callchain is:
191 # < check basic retryability prerequisites (e.g. no txn) >
192 # ->retry_handler
193 # ->storage->connected()
194 # ->ping
195 # So if we got here with the in_handler bit set - we won't break
196 # anything by a disconnect
197 if( $self->{_in_do_block_retry_handler} ) {
198 local $SIG{__WARN__} = sigwarn_silencer qr/disconnect invalidates .+? active statement/;
199 $self->disconnect;
200 }
201
202 # RV of _ping itself
203 0;
204 };
ecdf1ac8 205}
206
fb95dc4d 207package # hide from PAUSE
208 DBIx::Class::Storage::DBI::MSSQL::DateTime::Format;
209
fd323bf1 210my $datetime_format = '%Y-%m-%d %H:%M:%S.%3N'; # %F %T
fb95dc4d 211my $smalldatetime_format = '%Y-%m-%d %H:%M:%S';
212
213my ($datetime_parser, $smalldatetime_parser);
214
215sub parse_datetime {
216 shift;
217 require DateTime::Format::Strptime;
218 $datetime_parser ||= DateTime::Format::Strptime->new(
219 pattern => $datetime_format,
220 on_error => 'croak',
221 );
222 return $datetime_parser->parse_datetime(shift);
223}
224
225sub format_datetime {
226 shift;
227 require DateTime::Format::Strptime;
228 $datetime_parser ||= DateTime::Format::Strptime->new(
229 pattern => $datetime_format,
230 on_error => 'croak',
231 );
232 return $datetime_parser->format_datetime(shift);
233}
234
235sub parse_smalldatetime {
236 shift;
237 require DateTime::Format::Strptime;
238 $smalldatetime_parser ||= DateTime::Format::Strptime->new(
239 pattern => $smalldatetime_format,
240 on_error => 'croak',
241 );
242 return $smalldatetime_parser->parse_datetime(shift);
243}
244
245sub format_smalldatetime {
246 shift;
247 require DateTime::Format::Strptime;
248 $smalldatetime_parser ||= DateTime::Format::Strptime->new(
249 pattern => $smalldatetime_format,
250 on_error => 'croak',
251 );
252 return $smalldatetime_parser->format_datetime(shift);
253}
254
75d07914 2551;
3885cff6 256
75d07914 257=head1 NAME
3885cff6 258
5a77aa8b 259DBIx::Class::Storage::DBI::MSSQL - Base Class for Microsoft SQL Server support
260in DBIx::Class
3885cff6 261
75d07914 262=head1 SYNOPSIS
3885cff6 263
5a77aa8b 264This is the base class for Microsoft SQL Server support, used by
265L<DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server> and
266L<DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server>.
eb0323df 267
5a77aa8b 268=head1 IMPLEMENTATION NOTES
eb0323df 269
fd05d10a 270=head2 IDENTITY information
271
5a77aa8b 272Microsoft SQL Server supports three methods of retrieving the IDENTITY
273value for inserted row: IDENT_CURRENT, @@IDENTITY, and SCOPE_IDENTITY().
274SCOPE_IDENTITY is used here because it is the safest. However, it must
275be called is the same execute statement, not just the same connection.
eb0323df 276
5a77aa8b 277So, this implementation appends a SELECT SCOPE_IDENTITY() statement
278onto each INSERT to accommodate that requirement.
eb0323df 279
7b1b2582 280C<SELECT @@IDENTITY> can also be used by issuing:
281
282 $self->_identity_method('@@identity');
283
08cdc412 284it will only be used if SCOPE_IDENTITY() fails.
285
286This is more dangerous, as inserting into a table with an on insert trigger that
287inserts into another table with an identity will give erroneous results on
288recent versions of SQL Server.
7b1b2582 289
c84189e1 290=head2 identity insert
fd05d10a 291
292Be aware that we have tried to make things as simple as possible for our users.
c84189e1 293For MSSQL that means that when a user tries to create a row, while supplying an
294explicit value for an autoincrementing column, we will try to issue the
295appropriate database call to make this possible, namely C<SET IDENTITY_INSERT
296$table_name ON>. Unfortunately this operation in MSSQL requires the
297C<db_ddladmin> privilege, which is normally not included in the standard
298write-permissions.
fd05d10a 299
d74f2da9 300=head2 Ordered Subselects
6de07ea3 301
d74f2da9 302If you attempted the following query (among many others) in Microsoft SQL
303Server
6de07ea3 304
6de07ea3 305 $rs->search ({}, {
6de07ea3 306 prefetch => 'relation',
307 rows => 2,
308 offset => 3,
309 });
310
d74f2da9 311You may be surprised to receive an exception. The reason for this is a quirk
312in the MSSQL engine itself, and sadly doesn't have a sensible workaround due
313to the way DBIC is built. DBIC can do truly wonderful things with the aid of
314subselects, and does so automatically when necessary. The list of situations
315when a subselect is necessary is long and still changes often, so it can not
316be exhaustively enumerated here. The general rule of thumb is a joined
317L<has_many|DBIx::Class::Relationship/has_many> relationship with limit/group
318applied to the left part of the join.
319
320In its "pursuit of standards" Microsft SQL Server goes to great lengths to
321forbid the use of ordered subselects. This breaks a very useful group of
322searches like "Give me things number 4 to 6 (ordered by name), and prefetch
323all their relations, no matter how many". While there is a hack which fools
324the syntax checker, the optimizer may B<still elect to break the subselect>.
325Testing has determined that while such breakage does occur (the test suite
326contains an explicit test which demonstrates the problem), it is relative
327rare. The benefits of ordered subselects are on the other hand too great to be
328outright disabled for MSSQL.
6de07ea3 329
330Thus compromise between usability and perfection is the MSSQL-specific
69a8b315 331L<resultset attribute|DBIx::Class::ResultSet/ATTRIBUTES> C<unsafe_subselect_ok>.
6de07ea3 332It is deliberately not possible to set this on the Storage level, as the user
48580715 333should inspect (and preferably regression-test) the return of every such
d74f2da9 334ResultSet individually. The example above would work if written like:
335
336 $rs->search ({}, {
69a8b315 337 unsafe_subselect_ok => 1,
d74f2da9 338 prefetch => 'relation',
339 rows => 2,
340 offset => 3,
341 });
6de07ea3 342
343If it is possible to rewrite the search() in a way that will avoid the need
344for this flag - you are urged to do so. If DBIC internals insist that an
d74f2da9 345ordered subselect is necessary for an operation, and you believe there is a
48580715 346different/better way to get the same result - please file a bugreport.
6de07ea3 347
a2bd3796 348=head1 FURTHER QUESTIONS?
3885cff6 349
a2bd3796 350Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
3885cff6 351
a2bd3796 352=head1 COPYRIGHT AND LICENSE
3885cff6 353
a2bd3796 354This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
355by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
356redistribute it and/or modify it under the same terms as the
357L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.