Massive rewrite of bind handling, and overall simplification of ::Storage::DBI
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / ADO / Microsoft_SQL_Server.pm
1 package DBIx::Class::Storage::DBI::ADO::Microsoft_SQL_Server;
2
3 use strict;
4 use warnings;
5
6 use base qw/
7   DBIx::Class::Storage::DBI::ADO
8   DBIx::Class::Storage::DBI::MSSQL
9 /;
10 use mro 'c3';
11
12 =head1 NAME
13
14 DBIx::Class::Storage::DBI::ADO::Microsoft_SQL_Server - Support for Microsoft
15 SQL Server via DBD::ADO
16
17 =head1 SYNOPSIS
18
19 This subclass supports MSSQL server connections via L<DBD::ADO>.
20
21 =head1 DESCRIPTION
22
23 The MSSQL specific functionality is provided by
24 L<DBIx::Class::Storage::DBI::MSSQL>.
25
26 =head1 EXAMPLE DSN
27
28   dbi:ADO:provider=sqlncli10;server=EEEBOX\SQLEXPRESS
29
30 =head1 CAVEATS
31
32 =head2 identities
33
34 C<_identity_method> is set to C<@@identity>, as C<SCOPE_IDENTITY()> doesn't work
35 with L<DBD::ADO>. See L<DBIx::Class::Storage::DBI::MSSQL/IMPLEMENTATION NOTES>
36 for caveats regarding this.
37
38 =head2 truncation bug
39
40 There is a bug with MSSQL ADO providers where data gets truncated based on the
41 size of the bind sizes in the first prepare call:
42
43 L<https://rt.cpan.org/Ticket/Display.html?id=52048>
44
45 The C<ado_size> workaround is used (see L<DBD::ADO/"ADO Providers">) with the
46 approximate maximum size of the data_type of the bound column, or 8000 (maximum
47 VARCHAR size) if the data_type is not available.
48
49 This code is incomplete and may be buggy. Particularly, C<VARCHAR(MAX)> is not
50 supported yet. The data_type list for other DBs is also incomplete. Please
51 report problems (and send patches.)
52
53 =head2 fractional seconds
54
55 Fractional seconds with L<DBIx::Class::InflateColumn::DateTime> are not
56 currently supported, datetimes are truncated at the second.
57
58 =cut
59
60 __PACKAGE__->datetime_parser_type (
61   'DBIx::Class::Storage::DBI::ADO::Microsoft_SQL_Server::DateTime::Format'
62 );
63
64 sub _rebless {
65   my $self = shift;
66   $self->_identity_method('@@identity');
67 }
68
69 # work around a bug in the ADO driver - use the max VARCHAR size for all
70 # binds that do not specify one via bind_attributes_by_data_type()
71 sub _dbi_attrs_for_bind {
72   my $attrs = shift->next::method(@_);
73
74   for (@$attrs) {
75     $_->{ado_size} ||= 8000 if $_;
76   }
77
78   $attrs;
79 }
80
81 sub bind_attribute_by_data_type {
82   my ($self, $data_type) = @_;
83
84   ($data_type = lc($data_type)) =~ s/\s+.*//;
85
86   my $max_size =
87     $self->_mssql_max_data_type_representation_size_in_bytes->{$data_type};
88
89   my $res = {};
90   $res->{ado_size} = $max_size if $max_size;
91
92   return $res;
93 }
94
95 # approximate
96 # XXX needs to support varchar(max) and varbinary(max)
97 sub _mssql_max_data_type_representation_size_in_bytes {
98   my $self = shift;
99
100   my $blob_max = $self->_get_dbh->{LongReadLen} || 32768;
101
102   return +{
103 # MSSQL types
104     char => 8000,
105     varchar => 8000,
106     binary => 8000,
107     varbinary => 8000,
108     nchar => 8000,
109     nvarchar => 8000,
110     numeric => 100,
111     smallint => 100,
112     tinyint => 100,
113     smallmoney => 100,
114     bigint => 100,
115     bit => 100,
116     decimal => 100,
117     integer => 100,
118     int => 100,
119     money => 100,
120     float => 100,
121     real => 100,
122     uniqueidentifier => 100,
123     ntext => $blob_max,
124     text => $blob_max,
125     image => $blob_max,
126     date => 100,
127     datetime => 100,
128     datetime2 => 100,
129     datetimeoffset => 100,
130     smalldatetime => 100,
131     time => 100,
132     timestamp => 100,
133     cursor => 100,
134     hierarchyid => 100,
135     sql_variant => 100,
136     table => 100,
137     xml => $blob_max, # ???
138
139 # some non-MSSQL types
140     serial => 100,
141     bigserial => 100,
142     varchar2 => 8000,
143     blob => $blob_max,
144     clob => $blob_max,
145   }
146 }
147
148 package # hide from PAUSE
149   DBIx::Class::Storage::DBI::ADO::Microsoft_SQL_Server::DateTime::Format;
150
151 my $datetime_format = '%m/%d/%Y %I:%M:%S %p';
152 my $datetime_parser;
153
154 sub parse_datetime {
155   shift;
156   require DateTime::Format::Strptime;
157   $datetime_parser ||= DateTime::Format::Strptime->new(
158     pattern  => $datetime_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_parser ||= DateTime::Format::Strptime->new(
168     pattern  => $datetime_format,
169     on_error => 'croak',
170   );
171   return $datetime_parser->format_datetime(shift);
172 }
173
174 1;
175
176 =head1 AUTHOR
177
178 See L<DBIx::Class/AUTHOR> and 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
185 # vim:sts=2 sw=2: