12dfa5b91e35eb2c1dd883708e980cbe0d5e9bae
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Sybase / Microsoft_SQL_Server.pm
1 package DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server;
2
3 use strict;
4 use warnings;
5
6 use base qw/
7   DBIx::Class::Storage::DBI::Sybase
8   DBIx::Class::Storage::DBI::MSSQL
9 /;
10 use mro 'c3';
11
12 use DBIx::Class::Carp;
13 use namespace::clean;
14
15 =head1 NAME
16
17 DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server - Support for Microsoft
18 SQL Server via DBD::Sybase
19
20 =head1 SYNOPSIS
21
22 This subclass supports MSSQL server connections via L<DBD::Sybase>.
23
24 =head1 DESCRIPTION
25
26 This driver tries to determine whether your version of L<DBD::Sybase> and
27 supporting libraries (usually FreeTDS) support using placeholders, if not the
28 storage will be reblessed to
29 L<DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server::NoBindVars>.
30
31 The MSSQL specific functionality is provided by
32 L<DBIx::Class::Storage::DBI::MSSQL>.
33
34 =head1 METHODS
35
36 =cut
37
38 __PACKAGE__->datetime_parser_type(
39   'DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server::DateTime::Format'
40 );
41
42 sub _rebless {
43   my $self = shift;
44   my $dbh  = $self->_get_dbh;
45
46   return if ref $self ne __PACKAGE__;
47   if (not $self->_use_typeless_placeholders) {
48     carp_once <<'EOF' unless $ENV{DBIC_MSSQL_FREETDS_LOWVER_NOWARN};
49 Placeholders do not seem to be supported in your configuration of
50 DBD::Sybase/FreeTDS.
51
52 This means you are taking a large performance hit, as caching of prepared
53 statements is disabled.
54
55 Make sure to configure your server with "tds version" of 8.0 or 7.0 in
56 /etc/freetds/freetds.conf .
57
58 To turn off this warning, set the DBIC_MSSQL_FREETDS_LOWVER_NOWARN environment
59 variable.
60 EOF
61     require
62       DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server::NoBindVars;
63     bless $self,
64       'DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server::NoBindVars';
65     $self->_rebless;
66   }
67 }
68
69 sub _init {
70   my $self = shift;
71
72   $self->next::method(@_);
73
74   # work around massively broken freetds versions after 0.82
75   # - explicitly no scope_identity
76   # - no sth caching
77   #
78   # warn about the fact as well, do not provide a mechanism to shut it up
79   if ($self->_using_freetds and (my $ver = $self->_using_freetds_version||999) > 0.82) {
80     carp_once(
81       "Your DBD::Sybase was compiled against buggy FreeTDS version $ver. "
82     . 'Statement caching does not work and will be disabled.'
83     );
84
85     $self->_identity_method('@@identity');
86     $self->_no_scope_identity_query(1);
87     $self->disable_sth_caching(1);
88   }
89 }
90
91 # invoked only if DBD::Sybase is compiled against FreeTDS
92 sub _set_autocommit_stmt {
93   my ($self, $on) = @_;
94
95   return 'SET IMPLICIT_TRANSACTIONS ' . ($on ? 'OFF' : 'ON');
96 }
97
98 sub _get_server_version {
99   my $self = shift;
100
101   my $product_version = $self->_get_dbh->selectrow_hashref('master.dbo.xp_msver ProductVersion');
102
103   if ((my $version = $product_version->{Character_Value}) =~ /^(\d+)\./) {
104     return $version;
105   }
106   else {
107     $self->throw_exception(
108       "MSSQL Version Retrieval Failed, Your ProductVersion's Character_Value is missing or malformed!"
109     );
110   }
111 }
112
113 =head2 connect_call_datetime_setup
114
115 Used as:
116
117   on_connect_call => 'datetime_setup'
118
119 In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to set:
120
121   $dbh->syb_date_fmt('ISO_strict'); # output fmt: 2004-08-21T14:36:48.080Z
122
123 On connection for use with L<DBIx::Class::InflateColumn::DateTime>
124
125 This works for both C<DATETIME> and C<SMALLDATETIME> columns, although
126 C<SMALLDATETIME> columns only have minute precision.
127
128 =cut
129
130 sub connect_call_datetime_setup {
131   my $self = shift;
132   my $dbh = $self->_get_dbh;
133
134   if ($dbh->can('syb_date_fmt')) {
135     # amazingly, this works with FreeTDS
136     $dbh->syb_date_fmt('ISO_strict');
137   }
138   else{
139     carp_once
140       'Your DBD::Sybase is too old to support '
141     . 'DBIx::Class::InflateColumn::DateTime, please upgrade!';
142   }
143 }
144
145
146 package # hide from PAUSE
147   DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server::DateTime::Format;
148
149 my $datetime_parse_format  = '%Y-%m-%dT%H:%M:%S.%3NZ';
150 my $datetime_format_format = '%Y-%m-%d %H:%M:%S.%3N'; # %F %T
151
152 my ($datetime_parser, $datetime_formatter);
153
154 sub parse_datetime {
155   shift;
156   require DateTime::Format::Strptime;
157   $datetime_parser ||= DateTime::Format::Strptime->new(
158     pattern  => $datetime_parse_format,
159     on_error => 'croak',
160   );
161   return $datetime_parser->parse_datetime(shift);
162 }
163
164 sub format_datetime {
165   shift;
166   require DateTime::Format::Strptime;
167   $datetime_formatter ||= DateTime::Format::Strptime->new(
168     pattern  => $datetime_format_format,
169     on_error => 'croak',
170   );
171   return $datetime_formatter->format_datetime(shift);
172 }
173
174 1;
175
176 =head1 AUTHOR
177
178 See L<DBIx::Class/CONTRIBUTORS>.
179
180 =head1 LICENSE
181
182 You may distribute this code under the same terms as Perl itself.
183
184 =cut