1 package DBIx::Class::Storage::DBI::MSSQL;
7 DBIx::Class::Storage::DBI::UniqueIdentifier
8 DBIx::Class::Storage::DBI::IdentityInsert
13 use List::Util 'first';
16 __PACKAGE__->mk_group_accessors(simple => qw/
17 _identity _identity_method _no_scope_identity_query
20 __PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::MSSQL');
22 __PACKAGE__->sql_quote_char([qw/[ ]/]);
24 __PACKAGE__->datetime_parser_type (
25 'DBIx::Class::Storage::DBI::MSSQL::DateTime::Format'
28 __PACKAGE__->new_guid('NEWID()');
30 sub _sql_server_2005_or_higher {
31 if (exists $_[0]->_server_info->{normalized_dbms_version}) {
32 if ($_[0]->_server_info->{normalized_dbms_version} >= 9) {
41 sub _prep_for_execute {
43 my ($op, $ident, $args) = @_;
45 # cast MONEY values properly
46 if ($op eq 'insert' || $op eq 'update') {
47 my $fields = $args->[0];
49 my $colinfo = $ident->columns_info([keys %$fields]);
51 for my $col (keys %$fields) {
52 # $ident is a result source object with INSERT/UPDATE ops
54 $colinfo->{$col}{data_type}
56 $colinfo->{$col}{data_type} =~ /^money\z/i
58 my $val = $fields->{$col};
59 $fields->{$col} = \['CAST(? AS MONEY)', [ $col => $val ]];
64 my ($sql, $bind) = $self->next::method (@_);
66 # SELECT SCOPE_IDENTITY only works within a statement scope. We
67 # must try to always use this particular idiom first, as it is the
68 # only one that guarantees retrieving the correct id under high
69 # concurrency. When this fails we will fall back to whatever secondary
70 # retrieval method is specified in _identity_method, but at this
71 # point we don't have many guarantees we will get what we expected.
72 # http://msdn.microsoft.com/en-us/library/ms190315.aspx
73 # http://davidhayden.com/blog/dave/archive/2006/01/17/2736.aspx
75 not $self->_use_insert_returning and
76 $self->_perform_autoinc_retrieval and
77 not $self->_no_scope_identity_query
79 $sql .= "\nSELECT SCOPE_IDENTITY()";
88 # always list ctx - we need the $sth
89 my ($rv, $sth, @bind) = $self->next::method(@_);
91 if ($self->_perform_autoinc_retrieval) {
93 # attempt to bring back the result of SELECT SCOPE_IDENTITY() we tacked
94 # on in _prep_for_execute above
97 # we didn't even try on ftds
98 if (not $self->_use_insert_returning and
99 not $self->_no_scope_identity_query
101 ($identity) = try { $sth->fetchrow_array };
105 # SCOPE_IDENTITY failed, but we can do something else
106 if ( (! $identity) && $self->_identity_method) {
107 ($identity) = $self->_dbh->selectrow_array(
108 'select ' . $self->_identity_method
112 $self->_identity($identity);
115 return wantarray ? ($rv, $sth, @bind) : $rv;
118 sub last_insert_id { shift->_identity }
121 # MSSQL is retarded wrt ordered subselects. One needs to add a TOP
122 # to *all* subqueries, but one also *can't* use TOP 100 PERCENT
123 # http://sqladvice.com/forums/permalink/18496/22931/ShowThread.aspx#22931
125 sub _select_args_to_query {
126 #my ($self, $ident, $select, $cond, $attrs) = @_;
130 my $sql_bind = $self->next::method (@_);
132 # see if this is an ordered subquery
134 $$sql_bind->[0] !~ /^ \s* \( \s* SELECT \s+ TOP \s+ \d+ \s+ /xi
136 scalar $self->_extract_order_criteria ($attrs->{order_by})
138 $self->throw_exception(
139 'An ordered subselect encountered - this is not safe! Please see "Ordered Subselects" in DBIx::Class::Storage::DBI::MSSQL'
140 ) unless $attrs->{unsafe_subselect_ok};
142 $$sql_bind->[0] =~ s/^ \s* \( \s* SELECT (?=\s) / '(SELECT TOP ' . $self->sql_maker->__max_int /exi;
149 # savepoint syntax is the same as in Sybase ASE
151 sub _exec_svp_begin {
152 my ($self, $name) = @_;
154 $self->_dbh->do("SAVE TRANSACTION $name");
157 # A new SAVE TRANSACTION with the same name releases the previous one.
158 sub _exec_svp_release { 1 }
160 sub _exec_svp_rollback {
161 my ($self, $name) = @_;
163 $self->_dbh->do("ROLLBACK TRANSACTION $name");
166 sub sqlt_type { 'SQLServer' }
168 sub sql_limit_dialect {
171 my $supports_rno = $self->_sql_server_2005_or_higher;
173 unless (defined $supports_rno) {
174 # User is connecting via DBD::Sybase and has no permission to run
175 # stored procedures like xp_msver, or version detection failed for some
177 # So, we use a query to check if RNO is implemented.
179 $self->_get_dbh->selectrow_array('SELECT row_number() OVER (ORDER BY rand())');
184 return $supports_rno ? 'RowNumberOver' : 'Top';
190 my $dbh = $self->_dbh or return 0;
192 local $dbh->{RaiseError} = 1;
193 local $dbh->{PrintError} = 0;
196 $dbh->do('select 1');
203 # check for 2005 or greater here.
204 sub _use_insert_returning { $_[0]->_sql_server_2005_or_higher }
206 package # hide from PAUSE
207 DBIx::Class::Storage::DBI::MSSQL::DateTime::Format;
209 my $datetime_format = '%Y-%m-%d %H:%M:%S.%3N'; # %F %T
210 my $smalldatetime_format = '%Y-%m-%d %H:%M:%S';
212 my ($datetime_parser, $smalldatetime_parser);
216 require DateTime::Format::Strptime;
217 $datetime_parser ||= DateTime::Format::Strptime->new(
218 pattern => $datetime_format,
221 return $datetime_parser->parse_datetime(shift);
224 sub format_datetime {
226 require DateTime::Format::Strptime;
227 $datetime_parser ||= DateTime::Format::Strptime->new(
228 pattern => $datetime_format,
231 return $datetime_parser->format_datetime(shift);
234 sub parse_smalldatetime {
236 require DateTime::Format::Strptime;
237 $smalldatetime_parser ||= DateTime::Format::Strptime->new(
238 pattern => $smalldatetime_format,
241 return $smalldatetime_parser->parse_datetime(shift);
244 sub format_smalldatetime {
246 require DateTime::Format::Strptime;
247 $smalldatetime_parser ||= DateTime::Format::Strptime->new(
248 pattern => $smalldatetime_format,
251 return $smalldatetime_parser->format_datetime(shift);
258 DBIx::Class::Storage::DBI::MSSQL - Base Class for Microsoft SQL Server support
263 This is the base class for Microsoft SQL Server support, used by
264 L<DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server> and
265 L<DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server>.
267 =head1 IMPLEMENTATION NOTES
269 =head2 IDENTITY information
271 Microsoft SQL Server supports three methods of retrieving the IDENTITY
272 value for inserted row: IDENT_CURRENT, @@IDENTITY, and SCOPE_IDENTITY().
273 SCOPE_IDENTITY is used here because it is the safest. However, it must
274 be called is the same execute statement, not just the same connection.
276 So, this implementation appends a SELECT SCOPE_IDENTITY() statement
277 onto each INSERT to accommodate that requirement.
279 C<SELECT @@IDENTITY> can also be used by issuing:
281 $self->_identity_method('@@identity');
283 it will only be used if SCOPE_IDENTITY() fails.
285 This is more dangerous, as inserting into a table with an on insert trigger that
286 inserts into another table with an identity will give erroneous results on
287 recent versions of SQL Server.
289 =head2 identity insert
291 Be aware that we have tried to make things as simple as possible for our users.
292 For MSSQL that means that when a user tries to create a row, while supplying an
293 explicit value for an autoincrementing column, we will try to issue the
294 appropriate database call to make this possible, namely C<SET IDENTITY_INSERT
295 $table_name ON>. Unfortunately this operation in MSSQL requires the
296 C<db_ddladmin> privilege, which is normally not included in the standard
299 =head2 Ordered Subselects
301 If you attempted the following query (among many others) in Microsoft SQL
305 prefetch => 'relation',
310 You may be surprised to receive an exception. The reason for this is a quirk
311 in the MSSQL engine itself, and sadly doesn't have a sensible workaround due
312 to the way DBIC is built. DBIC can do truly wonderful things with the aid of
313 subselects, and does so automatically when necessary. The list of situations
314 when a subselect is necessary is long and still changes often, so it can not
315 be exhaustively enumerated here. The general rule of thumb is a joined
316 L<has_many|DBIx::Class::Relationship/has_many> relationship with limit/group
317 applied to the left part of the join.
319 In its "pursuit of standards" Microsft SQL Server goes to great lengths to
320 forbid the use of ordered subselects. This breaks a very useful group of
321 searches like "Give me things number 4 to 6 (ordered by name), and prefetch
322 all their relations, no matter how many". While there is a hack which fools
323 the syntax checker, the optimizer may B<still elect to break the subselect>.
324 Testing has determined that while such breakage does occur (the test suite
325 contains an explicit test which demonstrates the problem), it is relative
326 rare. The benefits of ordered subselects are on the other hand too great to be
327 outright disabled for MSSQL.
329 Thus compromise between usability and perfection is the MSSQL-specific
330 L<resultset attribute|DBIx::Class::ResultSet/ATTRIBUTES> C<unsafe_subselect_ok>.
331 It is deliberately not possible to set this on the Storage level, as the user
332 should inspect (and preferably regression-test) the return of every such
333 ResultSet individually. The example above would work if written like:
336 unsafe_subselect_ok => 1,
337 prefetch => 'relation',
342 If it is possible to rewrite the search() in a way that will avoid the need
343 for this flag - you are urged to do so. If DBIC internals insist that an
344 ordered subselect is necessary for an operation, and you believe there is a
345 different/better way to get the same result - please file a bugreport.
349 See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.
353 You may distribute this code under the same terms as Perl itself.