Much simpler
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Sybase.pm
CommitLineData
3885cff6 1package DBIx::Class::Storage::DBI::Sybase;
2
3use strict;
4use warnings;
2ad62d97 5
eabab5d0 6use base qw/
2f92e90b 7 DBIx::Class::Storage::DBI::Sybase::Common
07a5866e 8 DBIx::Class::Storage::DBI::AutoCast
eabab5d0 9/;
2ad62d97 10use mro 'c3';
6b1f5ef7 11use Carp::Clan qw/^DBIx::Class/;
289877b0 12use List::Util ();
6b1f5ef7 13
285baccb 14__PACKAGE__->mk_group_accessors('simple' =>
322b7a6b 15 qw/_identity _blob_log_on_update _insert_dbh _identity_method/
285baccb 16);
17
98259fe4 18=head1 NAME
19
928f0af8 20DBIx::Class::Storage::DBI::Sybase - Sybase support for DBIx::Class
98259fe4 21
22=head1 SYNOPSIS
23
24This subclass supports L<DBD::Sybase> for real Sybase databases. If you are
25using an MSSQL database via L<DBD::Sybase>, your storage will be reblessed to
26L<DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server>.
27
28=head1 DESCRIPTION
29
30If your version of Sybase does not support placeholders, then your storage
31will be reblessed to L<DBIx::Class::Storage::DBI::Sybase::NoBindVars>. You can
32also enable that driver explicitly, see the documentation for more details.
33
34With this driver there is unfortunately no way to get the C<last_insert_id>
310a0a0a 35without doing a C<SELECT MAX(col)>. This is done safely in a transaction
322b7a6b 36(locking the table.) See L</INSERTS WITH PLACEHOLDERS>.
98259fe4 37
61cfaef7 38A recommended L<DBIx::Class::Storage::DBI/connect_info> setting:
98259fe4 39
61cfaef7 40 on_connect_call => [['datetime_setup'], ['blob_setup', log_on_update => 0]]
98259fe4 41
42=head1 METHODS
43
44=cut
45
47d9646a 46sub _rebless {
b50a5275 47 my $self = shift;
c5ce7cd6 48
49 if (ref($self) eq 'DBIx::Class::Storage::DBI::Sybase') {
50 my $dbtype = eval {
2eef8633 51 @{$self->_get_dbh->selectrow_arrayref(qq{sp_server_info \@attribute_id=1})}[2]
c5ce7cd6 52 } || '';
53
54 my $exception = $@;
55 $dbtype =~ s/\W/_/gi;
56 my $subclass = "DBIx::Class::Storage::DBI::Sybase::${dbtype}";
57
58 if (!$exception && $dbtype && $self->load_optional_class($subclass)) {
59 bless $self, $subclass;
60 $self->_rebless;
5703eb14 61 } else { # real Sybase
62 my $no_bind_vars = 'DBIx::Class::Storage::DBI::Sybase::NoBindVars';
63
e97a6ee2 64 if ($self->using_freetds) {
a3a526cc 65 carp <<'EOF' unless $ENV{DBIC_SYBASE_FREETDS_NOWARN};
66
67You are using FreeTDS with Sybase.
5703eb14 68
a3a526cc 69We will do our best to support this configuration, but please consider this
70support experimental.
5703eb14 71
a3a526cc 72TEXT/IMAGE columns will definitely not work.
8c4b6c50 73
e97a6ee2 74You are encouraged to recompile DBD::Sybase with the Sybase Open Client libraries
a3a526cc 75instead.
5703eb14 76
77See perldoc DBIx::Class::Storage::DBI::Sybase for more details.
a3a526cc 78
79To turn off this warning set the DBIC_SYBASE_FREETDS_NOWARN environment
80variable.
5703eb14 81EOF
70ced519 82 if (not $self->_typeless_placeholders_supported) {
83 if ($self->_placeholders_supported) {
e97a6ee2 84 $self->auto_cast(1);
a3a526cc 85 } else {
86 $self->ensure_class_loaded($no_bind_vars);
87 bless $self, $no_bind_vars;
88 $self->_rebless;
89 }
90 }
0ac07712 91 }
75227502 92 elsif (not $self->_get_dbh->{syb_dynamic_supported}) {
0ac07712 93 # not necessarily FreeTDS, but no placeholders nevertheless
61cfaef7 94 $self->ensure_class_loaded($no_bind_vars);
95 bless $self, $no_bind_vars;
96 $self->_rebless;
310a0a0a 97 } elsif (not $self->_typeless_placeholders_supported) {
98# this is highly unlikely, but we check just in case
99 $self->auto_cast(1);
61cfaef7 100 }
47d9646a 101 }
c5ce7cd6 102 }
b50a5275 103}
104
37b17a93 105sub _init {
106 my $self = shift;
107 $self->_set_max_connect(256);
108
109 # based on LongReadLen in connect_info
110 $self->set_textsize if $self->using_freetds;
111}
112
a3a526cc 113# Make sure we have CHAINED mode turned on if AutoCommit is off in non-FreeTDS
114# DBD::Sybase (since we don't know how DBD::Sybase was compiled.) If however
115# we're using FreeTDS, CHAINED mode turns on an implicit transaction which we
116# only want when AutoCommit is off.
f6de7111 117sub _populate_dbh {
118 my $self = shift;
41c93b1b 119
a3a526cc 120 $self->next::method(@_);
41c93b1b 121
e97a6ee2 122 if (not $self->using_freetds) {
a3a526cc 123 $self->_dbh->{syb_chained_txn} = 1;
124 } else {
125 if ($self->_dbh_autocommit) {
126 $self->_dbh->do('SET CHAINED OFF');
127 } else {
128 $self->_dbh->do('SET CHAINED ON');
129 }
41c93b1b 130 }
131}
132
63d46bb3 133=head2 connect_call_blob_setup
134
135Used as:
136
61cfaef7 137 on_connect_call => [ [ 'blob_setup', log_on_update => 0 ] ]
63d46bb3 138
139Does C<< $dbh->{syb_binary_images} = 1; >> to return C<IMAGE> data as raw binary
140instead of as a hex string.
141
6636ad53 142Recommended.
143
fd5a07e4 144Also sets the C<log_on_update> value for blob write operations. The default is
145C<1>, but C<0> is better if your database is configured for it.
146
147See
148L<DBD::Sybase/Handling_IMAGE/TEXT_data_with_syb_ct_get_data()/syb_ct_send_data()>.
149
63d46bb3 150=cut
151
152sub connect_call_blob_setup {
153 my $self = shift;
fd5a07e4 154 my %args = @_;
63d46bb3 155 my $dbh = $self->_dbh;
156 $dbh->{syb_binary_images} = 1;
fd5a07e4 157
158 $self->_blob_log_on_update($args{log_on_update})
159 if exists $args{log_on_update};
160}
161
162sub _is_lob_type {
163 my $self = shift;
5703eb14 164 my $type = shift;
078a332f 165 $type && $type =~ /(?:text|image|lob|bytea|binary|memo)/i;
fd5a07e4 166}
167
285baccb 168sub _prep_for_execute {
169 my $self = shift;
170 my ($op, $extra_bind, $ident, $args) = @_;
171
172 my ($sql, $bind) = $self->next::method (@_);
173
174 if ($op eq 'insert') {
285baccb 175 my $table = $ident->from;
176
a3a526cc 177 my $bind_info = $self->_resolve_column_info(
178 $ident, [map $_->[0], @{$bind}]
179 );
0ac07712 180 my $identity_col = List::Util::first
181 { $bind_info->{$_}{is_auto_increment} }
182 (keys %$bind_info)
183 ;
285baccb 184
185 if ($identity_col) {
0ac07712 186 $sql = join ("\n",
187 "SET IDENTITY_INSERT $table ON",
188 $sql,
189 "SET IDENTITY_INSERT $table OFF",
190 );
191 }
192 else {
193 $identity_col = List::Util::first
194 { $ident->column_info($_)->{is_auto_increment} }
195 $ident->columns
196 ;
285baccb 197 }
198
199 if ($identity_col) {
285baccb 200 $sql =
285baccb 201 "$sql\n" .
a3a526cc 202 $self->_fetch_identity_sql($ident, $identity_col);
285baccb 203 }
204 }
205
206 return ($sql, $bind);
207}
208
0ac07712 209# Stolen from SQLT, with some modifications. This is a makeshift
210# solution before a sane type-mapping library is available, thus
211# the 'our' for easy overrides.
212our %TYPE_MAPPING = (
a3a526cc 213 number => 'numeric',
214 money => 'money',
215 varchar => 'varchar',
216 varchar2 => 'varchar',
217 timestamp => 'datetime',
218 text => 'varchar',
219 real => 'double precision',
220 comment => 'text',
221 bit => 'bit',
222 tinyint => 'smallint',
223 float => 'double precision',
224 serial => 'numeric',
225 bigserial => 'numeric',
226 boolean => 'varchar',
227 long => 'varchar',
228);
229
07a5866e 230sub _native_data_type {
a3a526cc 231 my ($self, $type) = @_;
232
233 $type = lc $type;
c9d9c670 234 $type =~ s/\s* identity//x;
a3a526cc 235
236 return uc($TYPE_MAPPING{$type} || $type);
237}
238
285baccb 239sub _fetch_identity_sql {
240 my ($self, $source, $col) = @_;
241
242 return "SELECT MAX($col) FROM ".$source->from;
243}
244
245sub _execute {
246 my $self = shift;
247 my ($op) = @_;
248
249 my ($rv, $sth, @bind) = $self->dbh_do($self->can('_dbh_execute'), @_);
250
251 if ($op eq 'insert') {
252 $self->_identity($sth->fetchrow_array);
253 $sth->finish;
254 }
255
256 return wantarray ? ($rv, $sth, @bind) : $rv;
257}
258
259sub last_insert_id { shift->_identity }
260
aee988d2 261# handles TEXT/IMAGE and transaction for last_insert_id
fd5a07e4 262sub insert {
0ac07712 263 my $self = shift;
58e3556d 264 my ($source, $to_insert) = @_;
7d17f469 265
266 my $blob_cols = $self->_remove_blob_cols($source, $to_insert);
267
322b7a6b 268# insert+blob insert done atomically, on _insert_dbh
269 (my ($guard), local ($self->{_dbh})) = do {
270 $self->_insert_dbh($self->_connect(@{ $self->_dbi_connect_info }))
271 unless $self->_insert_dbh;
272
273 my $new_guard = $self->txn_scope_guard;
274
275# _dbh_begin_work may reconnect, if so we need to update _insert_dbh
276 $self->_insert_dbh($self->_dbh);
277
278 ($new_guard, $self->_insert_dbh)
279 } if $blob_cols;
aee988d2 280
310a0a0a 281 my $need_last_insert_id = 0;
282
283 my ($identity_col) =
284 map $_->[0],
285 grep $_->[1]{is_auto_increment},
286 map [ $_, $source->column_info($_) ],
287 $source->columns;
288
289 $need_last_insert_id = 1
290 if $identity_col && (not exists $to_insert->{$identity_col});
291
0ac07712 292 # We have to do the insert in a transaction to avoid race conditions with the
293 # SELECT MAX(COL) identity method used when placeholders are enabled.
f6de7111 294 my $updated_cols = do {
322b7a6b 295 no warnings 'uninitialized';
85aa43a2 296 if (
322b7a6b 297 $need_last_insert_id &&
298 $self->_identity_method ne '@@IDENTITY' &&
299 !$self->{transaction_depth}
85aa43a2 300 ) {
51ac7136 301 $self->_insert_dbh($self->_connect(@{ $self->_dbi_connect_info }))
302 unless $self->_insert_dbh;
c9d9c670 303 local $self->{_dbh} = $self->_insert_dbh;
322b7a6b 304
0ac07712 305 my $guard = $self->txn_scope_guard;
322b7a6b 306
307# _dbh_begin_work may reconnect, if so we need to update _insert_dbh
308 $self->_insert_dbh($self->_dbh);
309
0ac07712 310 my $upd_cols = $self->next::method (@_);
311 $guard->commit;
322b7a6b 312
58e3556d 313 $upd_cols;
0ac07712 314 }
315 else {
316 $self->next::method(@_);
a3a526cc 317 }
f6de7111 318 };
7d17f469 319
c966cf1b 320 $self->_insert_blobs($source, $blob_cols, $to_insert) if $blob_cols;
7d17f469 321
aee988d2 322 $guard->commit if $guard;
323
7d17f469 324 return $updated_cols;
325}
326
078a332f 327sub update {
0ac07712 328 my $self = shift;
5370e479 329 my ($source, $fields, $where) = @_;
0ac07712 330
331 my $wantarray = wantarray;
078a332f 332
333 my $blob_cols = $self->_remove_blob_cols($source, $fields);
334
aee988d2 335# update+blob update(s) done atomically
c966cf1b 336 my $guard = $self->txn_scope_guard if $blob_cols;
aee988d2 337
078a332f 338 my @res;
339 if ($wantarray) {
0ac07712 340 @res = $self->next::method(@_);
341 }
342 elsif (defined $wantarray) {
343 $res[0] = $self->next::method(@_);
344 }
345 else {
346 $self->next::method(@_);
078a332f 347 }
348
c966cf1b 349 $self->_update_blobs($source, $blob_cols, $where) if $blob_cols;
078a332f 350
c966cf1b 351 $guard->commit if $guard;
aee988d2 352
078a332f 353 return $wantarray ? @res : $res[0];
354}
7d17f469 355
356sub _remove_blob_cols {
357 my ($self, $source, $fields) = @_;
fd5a07e4 358
359 my %blob_cols;
360
7d17f469 361 for my $col (keys %$fields) {
9b3dabe0 362 if ($self->_is_lob_type($source->column_info($col)->{data_type})) {
363 $blob_cols{$col} = delete $fields->{$col};
364 $fields->{$col} = \"''";
365 }
fd5a07e4 366 }
367
c966cf1b 368 return keys %blob_cols ? \%blob_cols : undef;
fd5a07e4 369}
370
371sub _update_blobs {
5370e479 372 my ($self, $source, $blob_cols, $where) = @_;
078a332f 373
374 my (@primary_cols) = $source->primary_columns;
375
376 croak "Cannot update TEXT/IMAGE column(s) without a primary key"
377 unless @primary_cols;
378
379# check if we're updating a single row by PK
380 my $pk_cols_in_where = 0;
381 for my $col (@primary_cols) {
5370e479 382 $pk_cols_in_where++ if defined $where->{$col};
078a332f 383 }
384 my @rows;
385
386 if ($pk_cols_in_where == @primary_cols) {
387 my %row_to_update;
5370e479 388 @row_to_update{@primary_cols} = @{$where}{@primary_cols};
078a332f 389 @rows = \%row_to_update;
390 } else {
391 my $rs = $source->resultset->search(
5370e479 392 $where,
078a332f 393 {
394 result_class => 'DBIx::Class::ResultClass::HashRefInflator',
395 select => \@primary_cols
396 }
397 );
398 @rows = $rs->all; # statement must finish
399 }
400
401 for my $row (@rows) {
402 $self->_insert_blobs($source, $blob_cols, $row);
403 }
404}
405
406sub _insert_blobs {
407 my ($self, $source, $blob_cols, $row) = @_;
75227502 408 my $dbh = $self->_get_dbh;
fd5a07e4 409
410 my $table = $source->from;
411
078a332f 412 my %row = %$row;
fd5a07e4 413 my (@primary_cols) = $source->primary_columns;
414
9b3dabe0 415 croak "Cannot update TEXT/IMAGE column(s) without a primary key"
fd5a07e4 416 unless @primary_cols;
417
078a332f 418 if ((grep { defined $row{$_} } @primary_cols) != @primary_cols) {
9b3dabe0 419 if (@primary_cols == 1) {
420 my $col = $primary_cols[0];
078a332f 421 $row{$col} = $self->last_insert_id($source, $col);
9b3dabe0 422 } else {
423 croak "Cannot update TEXT/IMAGE column(s) without primary key values";
424 }
425 }
fd5a07e4 426
427 for my $col (keys %$blob_cols) {
428 my $blob = $blob_cols->{$col};
429
a3a526cc 430 my %where = map { ($_, $row{$_}) } @primary_cols;
431 my $cursor = $source->resultset->search(\%where, {
432 select => [$col]
433 })->cursor;
434 $cursor->next;
5137d252 435 my $sth = $cursor->sth;
fd5a07e4 436
437 eval {
a3a526cc 438 do {
fd5a07e4 439 $sth->func('CS_GET', 1, 'ct_data_info') or die $sth->errstr;
a3a526cc 440 } while $sth->fetch;
441
fd5a07e4 442 $sth->func('ct_prepare_send') or die $sth->errstr;
443
444 my $log_on_update = $self->_blob_log_on_update;
445 $log_on_update = 1 if not defined $log_on_update;
446
447 $sth->func('CS_SET', 1, {
448 total_txtlen => length($blob),
449 log_on_update => $log_on_update
450 }, 'ct_data_info') or die $sth->errstr;
451
452 $sth->func($blob, length($blob), 'ct_send_data') or die $sth->errstr;
453
454 $sth->func('ct_finish_send') or die $sth->errstr;
455 };
456 my $exception = $@;
a3a526cc 457 $sth->finish if $sth;
458 if ($exception) {
e97a6ee2 459 if ($self->using_freetds) {
0ac07712 460 croak (
461 'TEXT/IMAGE operation failed, probably because you are using FreeTDS: '
462 . $exception
463 );
a3a526cc 464 } else {
465 croak $exception;
466 }
467 }
fd5a07e4 468 }
63d46bb3 469}
470
9539eeb1 471=head2 connect_call_datetime_setup
472
473Used as:
474
475 on_connect_call => 'datetime_setup'
476
477In L<DBIx::Class::Storage::DBI/connect_info> to set:
478
3abafb11 479 $dbh->syb_date_fmt('ISO_strict'); # output fmt: 2004-08-21T14:36:48.080Z
480 $dbh->do('set dateformat mdy'); # input fmt: 08/13/1979 18:08:55.080
9539eeb1 481
482On connection for use with L<DBIx::Class::InflateColumn::DateTime>, using
3abafb11 483L<DateTime::Format::Sybase>, which you will need to install.
484
485This works for both C<DATETIME> and C<SMALLDATETIME> columns, although
486C<SMALLDATETIME> columns only have minute precision.
9539eeb1 487
488=cut
489
9041a97a 490{
491 my $old_dbd_warned = 0;
492
9539eeb1 493 sub connect_call_datetime_setup {
6b1f5ef7 494 my $self = shift;
6b1f5ef7 495 my $dbh = $self->_dbh;
496
497 if ($dbh->can('syb_date_fmt')) {
0ac07712 498 # amazingly, this works with FreeTDS
6b1f5ef7 499 $dbh->syb_date_fmt('ISO_strict');
500 } elsif (not $old_dbd_warned) {
501 carp "Your DBD::Sybase is too old to support ".
502 "DBIx::Class::InflateColumn::DateTime, please upgrade!";
503 $old_dbd_warned = 1;
504 }
505
e97a6ee2 506 $dbh->do('SET DATEFORMAT mdy');
c5ce7cd6 507
6b1f5ef7 508 1;
c5ce7cd6 509 }
6b1f5ef7 510}
511
6636ad53 512sub datetime_parser_type { "DateTime::Format::Sybase" }
513
e97a6ee2 514# ->begin_work and such have no effect with FreeTDS but we run them anyway to
515# let the DBD keep any state it needs to.
516#
517# If they ever do start working, the extra statements will do no harm (because
518# Sybase supports nested transactions.)
a3a526cc 519
520sub _dbh_begin_work {
521 my $self = shift;
e97a6ee2 522 $self->next::method(@_);
523 if ($self->using_freetds) {
75227502 524 $self->_get_dbh->do('BEGIN TRAN');
a3a526cc 525 }
526}
527
528sub _dbh_commit {
529 my $self = shift;
e97a6ee2 530 if ($self->using_freetds) {
a3a526cc 531 $self->_dbh->do('COMMIT');
532 }
e97a6ee2 533 return $self->next::method(@_);
a3a526cc 534}
535
536sub _dbh_rollback {
537 my $self = shift;
e97a6ee2 538 if ($self->using_freetds) {
a3a526cc 539 $self->_dbh->do('ROLLBACK');
540 }
e97a6ee2 541 return $self->next::method(@_);
a3a526cc 542}
543
1816be4f 544# savepoint support using ASE syntax
545
546sub _svp_begin {
547 my ($self, $name) = @_;
548
75227502 549 $self->_get_dbh->do("SAVE TRANSACTION $name");
1816be4f 550}
551
552# A new SAVE TRANSACTION with the same name releases the previous one.
553sub _svp_release { 1 }
554
555sub _svp_rollback {
556 my ($self, $name) = @_;
557
75227502 558 $self->_get_dbh->do("ROLLBACK TRANSACTION $name");
1816be4f 559}
560
3885cff6 5611;
562
efe75aaa 563=head1 Schema::Loader Support
564
565There is an experimental branch of L<DBIx::Class::Schema::Loader> that will
566allow you to dump a schema from most (if not all) versions of Sybase.
567
568It is available via subversion from:
569
07a5866e 570 http://dev.catalyst.perl.org/repos/bast/branches/DBIx-Class-Schema-Loader/current/
efe75aaa 571
e97a6ee2 572=head1 FreeTDS
573
574This driver supports L<DBD::Sybase> compiled against FreeTDS
575(L<http://www.freetds.org/>) to the best of our ability, however it is
576recommended that you recompile L<DBD::Sybase> against the Sybase Open Client
577libraries. They are a part of the Sybase ASE distribution:
578
579The Open Client FAQ is here:
580L<http://www.isug.com/Sybase_FAQ/ASE/section7.html>.
581
582Sybase ASE for Linux (which comes with the Open Client libraries) may be
583downloaded here: L<http://response.sybase.com/forms/ASE_Linux_Download>.
584
585To see if you're using FreeTDS check C<< $schema->storage->using_freetds >>, or run:
586
587 perl -MDBI -le 'my $dbh = DBI->connect($dsn, $user, $pass); print $dbh->{syb_oc_version}'
588
589Some versions of the libraries involved will not support placeholders, in which
590case the storage will be reblessed to
591L<DBIx::Class::Storage::DBI::Sybase::NoBindVars>.
592
07a5866e 593In some configurations, placeholders will work but will throw implicit type
e97a6ee2 594conversion errors for anything that's not expecting a string. In such a case,
07a5866e 595the C<auto_cast> option from L<DBIx::Class::Storage::DBI::AutoCast> is
596automatically set, which you may enable on connection with
597L<DBIx::Class::Storage::DBI::AutoCast/connect_call_set_auto_cast>. The type info
598for the C<CAST>s is taken from the L<DBIx::Class::ResultSource/data_type>
599definitions in your Result classes, and are mapped to a Sybase type (if it isn't
600already) using a mapping based on L<SQL::Translator>.
e97a6ee2 601
602In other configurations, placeholers will work just as they do with the Sybase
603Open Client libraries.
604
605Inserts or updates of TEXT/IMAGE columns will B<NOT> work with FreeTDS.
606
322b7a6b 607=head1 INSERTS WITH PLACEHOLDERS
608
609With placeholders enabled, inserts are done in a transaction so that there are
610no concurrency issues with getting the inserted identity value using
611C<SELECT MAX(col)>, which is the only way to get the C<IDENTITY> value in this
612mode.
613
614When using C<DBIx::Class::Storage::DBI::Sybase::NoBindVars> transactions are
615disabled, as there are no concurrency issues with C<SELECT @@IDENTITY> as it's a
616session variable.
617
166c6561 618=head1 TRANSACTIONS
619
620Due to limitations of the TDS protocol, L<DBD::Sybase>, or both; you cannot
621begin a transaction while there are active cursors. An active cursor is, for
622example, a L<ResultSet|DBIx::Class::ResultSet> that has been executed using
623C<next> or C<first> but has not been exhausted or
75227502 624L<reset|DBIx::Class::ResultSet/reset>.
166c6561 625
322b7a6b 626For example, this will not work:
627
628 $schema->txn_do(sub {
629 my $rs = $schema->resultset('Book');
630 while (my $row = $rs->next) {
631 $schema->resultset('MetaData')->create({
632 book_id => $row->id,
633 ...
634 });
635 }
636 });
637
166c6561 638Transactions done for inserts in C<AutoCommit> mode when placeholders are in use
51ac7136 639are not affected, as they use an extra database handle to do the insert.
75227502 640
641Some workarounds:
642
643=over 4
644
75227502 645=item * use L<DBIx::Class::Storage::DBI::Replicated>
646
647=item * L<connect|DBIx::Class::Schema/connect> another L<Schema|DBIx::Class::Schema>
648
649=item * load the data from your cursor with L<DBIx::Class::ResultSet/all>
650
75227502 651=back
166c6561 652
41c93b1b 653=head1 MAXIMUM CONNECTIONS
654
e97a6ee2 655The TDS protocol makes separate connections to the server for active statements
656in the background. By default the number of such connections is limited to 25,
657on both the client side and the server side.
41c93b1b 658
e97a6ee2 659This is a bit too low for a complex L<DBIx::Class> application, so on connection
660the client side setting is set to C<256> (see L<DBD::Sybase/maxConnect>.) You
661can override it to whatever setting you like in the DSN.
41c93b1b 662
663See
664L<http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.ase_15.0.sag1/html/sag1/sag1272.htm>
665for information on changing the setting on the server side.
666
c5ce7cd6 667=head1 DATES
668
3abafb11 669See L</connect_call_datetime_setup> to setup date formats
670for L<DBIx::Class::InflateColumn::DateTime>.
c5ce7cd6 671
e97a6ee2 672=head1 TEXT/IMAGE COLUMNS
63d46bb3 673
a3a526cc 674L<DBD::Sybase> compiled with FreeTDS will B<NOT> allow you to insert or update
675C<TEXT/IMAGE> columns.
676
e97a6ee2 677Setting C<< $dbh->{LongReadLen} >> will also not work with FreeTDS use either:
678
679 $schema->storage->dbh->do("SET TEXTSIZE $bytes");
a3a526cc 680
e97a6ee2 681or
682
683 $schema->storage->set_textsize($bytes);
a3a526cc 684
685instead.
5703eb14 686
e97a6ee2 687However, the C<LongReadLen> you pass in
688L<DBIx::Class::Storage::DBI/connect_info> is used to execute the equivalent
689C<SET TEXTSIZE> command on connection.
690
63d46bb3 691See L</connect_call_blob_setup> for a L<DBIx::Class::Storage::DBI/connect_info>
692setting you need to work with C<IMAGE> columns.
693
58e3556d 694=head1 AUTHOR
3885cff6 695
7e8cecc1 696See L<DBIx::Class/CONTRIBUTORS>.
c5ce7cd6 697
3885cff6 698=head1 LICENSE
699
700You may distribute this code under the same terms as Perl itself.
701
702=cut
c5ce7cd6 703# vim:sts=2 sw=2: