remove Sub::Name hack for method dispatch, pass $next instead
[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
c453ddd9 242 return sprintf ("SELECT MAX(%s) FROM %s",
243 map { $self->sql_maker->_quote ($_) } ($col, $source->from)
244 );
285baccb 245}
246
247sub _execute {
248 my $self = shift;
249 my ($op) = @_;
250
251 my ($rv, $sth, @bind) = $self->dbh_do($self->can('_dbh_execute'), @_);
252
253 if ($op eq 'insert') {
254 $self->_identity($sth->fetchrow_array);
255 $sth->finish;
256 }
257
258 return wantarray ? ($rv, $sth, @bind) : $rv;
259}
260
261sub last_insert_id { shift->_identity }
262
aee988d2 263# handles TEXT/IMAGE and transaction for last_insert_id
fd5a07e4 264sub insert {
0ac07712 265 my $self = shift;
58e3556d 266 my ($source, $to_insert) = @_;
7d17f469 267
268 my $blob_cols = $self->_remove_blob_cols($source, $to_insert);
269
c453ddd9 270 my $identity_col = List::Util::first
271 { $source->column_info($_)->{is_auto_increment} }
272 $source->columns;
322b7a6b 273
c453ddd9 274 # do we need the horrific SELECT MAX(COL) hack?
275 my $dumb_last_insert_id =
276 ( $identity_col
277 && (not exists $to_insert->{$identity_col})
278 && ($self->_identity_method||'') ne '@@IDENTITY'
279 ) ? 1 : 0;
280
759ca0fe 281 my $next = $self->next::can;
282
c453ddd9 283 # we are already in a transaction, or there are no blobs
284 # and we don't need the PK - just (try to) do it
285 if ($self->{transaction_depth}
286 || (!$blob_cols && !$dumb_last_insert_id)
287 ) {
759ca0fe 288 return $self->_insert (
289 $source, $to_insert, $blob_cols, $identity_col, $next
290 );
c453ddd9 291 }
322b7a6b 292
c453ddd9 293 # this is tricky: a transaction needs to take place if we need
294 # either a last_insert_id or we will be doing blob insert.
295 # This will happen on a *seperate* connection, thus the local()
296 # acrobatics
322b7a6b 297
c453ddd9 298 local $self->{_dbh};
aee988d2 299
c453ddd9 300 # localize so it appears right if we blow out with an exception
301 local $self->{transaction_depth} = 0;
310a0a0a 302
c453ddd9 303 $self->_insert_dbh($self->_connect(@{ $self->_dbi_connect_info }))
304 unless $self->_insert_dbh;
310a0a0a 305
c453ddd9 306 $self->{_dbh} = $self->_insert_dbh;
307 my $guard = $self->txn_scope_guard;
310a0a0a 308
c453ddd9 309 # _dbh_begin_work in the guard may reconnect,
310 # so we update the accessor just in case
311 $self->_insert_dbh($self->_dbh);
322b7a6b 312
759ca0fe 313 my $updated_cols = $self->_insert (
314 $source, $to_insert, $blob_cols, $identity_col, $next
315 );
322b7a6b 316
c453ddd9 317 $guard->commit;
322b7a6b 318
c453ddd9 319 return $updated_cols;
322b7a6b 320
c453ddd9 321}
7d17f469 322
c453ddd9 323sub _insert {
759ca0fe 324 my ($self, $source, $to_insert, $blob_cols, $identity_col, $next) = @_;
7d17f469 325
759ca0fe 326 my $updated_cols = $self->$next ($source, $to_insert);
c453ddd9 327
328 my $final_row = {
329 $identity_col => $self->last_insert_id($source, $identity_col),
330 %$to_insert,
331 %$updated_cols,
332 };
333
334 $self->_insert_blobs ($source, $blob_cols, $final_row) if $blob_cols;
aee988d2 335
7d17f469 336 return $updated_cols;
337}
338
078a332f 339sub update {
0ac07712 340 my $self = shift;
5370e479 341 my ($source, $fields, $where) = @_;
0ac07712 342
343 my $wantarray = wantarray;
078a332f 344
345 my $blob_cols = $self->_remove_blob_cols($source, $fields);
346
aee988d2 347# update+blob update(s) done atomically
c966cf1b 348 my $guard = $self->txn_scope_guard if $blob_cols;
aee988d2 349
078a332f 350 my @res;
351 if ($wantarray) {
0ac07712 352 @res = $self->next::method(@_);
353 }
354 elsif (defined $wantarray) {
355 $res[0] = $self->next::method(@_);
356 }
357 else {
358 $self->next::method(@_);
078a332f 359 }
360
c966cf1b 361 $self->_update_blobs($source, $blob_cols, $where) if $blob_cols;
078a332f 362
c966cf1b 363 $guard->commit if $guard;
aee988d2 364
078a332f 365 return $wantarray ? @res : $res[0];
366}
7d17f469 367
368sub _remove_blob_cols {
369 my ($self, $source, $fields) = @_;
fd5a07e4 370
371 my %blob_cols;
372
7d17f469 373 for my $col (keys %$fields) {
9b3dabe0 374 if ($self->_is_lob_type($source->column_info($col)->{data_type})) {
375 $blob_cols{$col} = delete $fields->{$col};
376 $fields->{$col} = \"''";
377 }
fd5a07e4 378 }
379
c966cf1b 380 return keys %blob_cols ? \%blob_cols : undef;
fd5a07e4 381}
382
383sub _update_blobs {
5370e479 384 my ($self, $source, $blob_cols, $where) = @_;
078a332f 385
386 my (@primary_cols) = $source->primary_columns;
387
388 croak "Cannot update TEXT/IMAGE column(s) without a primary key"
389 unless @primary_cols;
390
391# check if we're updating a single row by PK
392 my $pk_cols_in_where = 0;
393 for my $col (@primary_cols) {
5370e479 394 $pk_cols_in_where++ if defined $where->{$col};
078a332f 395 }
396 my @rows;
397
398 if ($pk_cols_in_where == @primary_cols) {
399 my %row_to_update;
5370e479 400 @row_to_update{@primary_cols} = @{$where}{@primary_cols};
078a332f 401 @rows = \%row_to_update;
402 } else {
403 my $rs = $source->resultset->search(
5370e479 404 $where,
078a332f 405 {
406 result_class => 'DBIx::Class::ResultClass::HashRefInflator',
ba1f339d 407 columns => \@primary_cols
078a332f 408 }
409 );
410 @rows = $rs->all; # statement must finish
411 }
412
413 for my $row (@rows) {
414 $self->_insert_blobs($source, $blob_cols, $row);
415 }
416}
417
418sub _insert_blobs {
419 my ($self, $source, $blob_cols, $row) = @_;
75227502 420 my $dbh = $self->_get_dbh;
fd5a07e4 421
422 my $table = $source->from;
423
078a332f 424 my %row = %$row;
fd5a07e4 425 my (@primary_cols) = $source->primary_columns;
426
9b3dabe0 427 croak "Cannot update TEXT/IMAGE column(s) without a primary key"
fd5a07e4 428 unless @primary_cols;
429
078a332f 430 if ((grep { defined $row{$_} } @primary_cols) != @primary_cols) {
c453ddd9 431 croak "Cannot update TEXT/IMAGE column(s) without primary key values";
9b3dabe0 432 }
fd5a07e4 433
434 for my $col (keys %$blob_cols) {
435 my $blob = $blob_cols->{$col};
436
a3a526cc 437 my %where = map { ($_, $row{$_}) } @primary_cols;
438 my $cursor = $source->resultset->search(\%where, {
439 select => [$col]
440 })->cursor;
441 $cursor->next;
5137d252 442 my $sth = $cursor->sth;
fd5a07e4 443
444 eval {
a3a526cc 445 do {
fd5a07e4 446 $sth->func('CS_GET', 1, 'ct_data_info') or die $sth->errstr;
a3a526cc 447 } while $sth->fetch;
448
fd5a07e4 449 $sth->func('ct_prepare_send') or die $sth->errstr;
450
451 my $log_on_update = $self->_blob_log_on_update;
452 $log_on_update = 1 if not defined $log_on_update;
453
454 $sth->func('CS_SET', 1, {
455 total_txtlen => length($blob),
456 log_on_update => $log_on_update
457 }, 'ct_data_info') or die $sth->errstr;
458
459 $sth->func($blob, length($blob), 'ct_send_data') or die $sth->errstr;
460
461 $sth->func('ct_finish_send') or die $sth->errstr;
462 };
463 my $exception = $@;
a3a526cc 464 $sth->finish if $sth;
465 if ($exception) {
e97a6ee2 466 if ($self->using_freetds) {
0ac07712 467 croak (
468 'TEXT/IMAGE operation failed, probably because you are using FreeTDS: '
469 . $exception
470 );
a3a526cc 471 } else {
472 croak $exception;
473 }
474 }
fd5a07e4 475 }
63d46bb3 476}
477
9539eeb1 478=head2 connect_call_datetime_setup
479
480Used as:
481
482 on_connect_call => 'datetime_setup'
483
484In L<DBIx::Class::Storage::DBI/connect_info> to set:
485
3abafb11 486 $dbh->syb_date_fmt('ISO_strict'); # output fmt: 2004-08-21T14:36:48.080Z
487 $dbh->do('set dateformat mdy'); # input fmt: 08/13/1979 18:08:55.080
9539eeb1 488
489On connection for use with L<DBIx::Class::InflateColumn::DateTime>, using
3abafb11 490L<DateTime::Format::Sybase>, which you will need to install.
491
492This works for both C<DATETIME> and C<SMALLDATETIME> columns, although
493C<SMALLDATETIME> columns only have minute precision.
9539eeb1 494
495=cut
496
9041a97a 497{
498 my $old_dbd_warned = 0;
499
9539eeb1 500 sub connect_call_datetime_setup {
6b1f5ef7 501 my $self = shift;
6b1f5ef7 502 my $dbh = $self->_dbh;
503
504 if ($dbh->can('syb_date_fmt')) {
0ac07712 505 # amazingly, this works with FreeTDS
6b1f5ef7 506 $dbh->syb_date_fmt('ISO_strict');
507 } elsif (not $old_dbd_warned) {
508 carp "Your DBD::Sybase is too old to support ".
509 "DBIx::Class::InflateColumn::DateTime, please upgrade!";
510 $old_dbd_warned = 1;
511 }
512
e97a6ee2 513 $dbh->do('SET DATEFORMAT mdy');
c5ce7cd6 514
6b1f5ef7 515 1;
c5ce7cd6 516 }
6b1f5ef7 517}
518
6636ad53 519sub datetime_parser_type { "DateTime::Format::Sybase" }
520
e97a6ee2 521# ->begin_work and such have no effect with FreeTDS but we run them anyway to
522# let the DBD keep any state it needs to.
523#
524# If they ever do start working, the extra statements will do no harm (because
525# Sybase supports nested transactions.)
a3a526cc 526
527sub _dbh_begin_work {
528 my $self = shift;
e97a6ee2 529 $self->next::method(@_);
530 if ($self->using_freetds) {
75227502 531 $self->_get_dbh->do('BEGIN TRAN');
a3a526cc 532 }
533}
534
535sub _dbh_commit {
536 my $self = shift;
e97a6ee2 537 if ($self->using_freetds) {
a3a526cc 538 $self->_dbh->do('COMMIT');
539 }
e97a6ee2 540 return $self->next::method(@_);
a3a526cc 541}
542
543sub _dbh_rollback {
544 my $self = shift;
e97a6ee2 545 if ($self->using_freetds) {
a3a526cc 546 $self->_dbh->do('ROLLBACK');
547 }
e97a6ee2 548 return $self->next::method(@_);
a3a526cc 549}
550
1816be4f 551# savepoint support using ASE syntax
552
553sub _svp_begin {
554 my ($self, $name) = @_;
555
75227502 556 $self->_get_dbh->do("SAVE TRANSACTION $name");
1816be4f 557}
558
559# A new SAVE TRANSACTION with the same name releases the previous one.
560sub _svp_release { 1 }
561
562sub _svp_rollback {
563 my ($self, $name) = @_;
564
75227502 565 $self->_get_dbh->do("ROLLBACK TRANSACTION $name");
1816be4f 566}
567
3885cff6 5681;
569
efe75aaa 570=head1 Schema::Loader Support
571
572There is an experimental branch of L<DBIx::Class::Schema::Loader> that will
573allow you to dump a schema from most (if not all) versions of Sybase.
574
575It is available via subversion from:
576
07a5866e 577 http://dev.catalyst.perl.org/repos/bast/branches/DBIx-Class-Schema-Loader/current/
efe75aaa 578
e97a6ee2 579=head1 FreeTDS
580
581This driver supports L<DBD::Sybase> compiled against FreeTDS
582(L<http://www.freetds.org/>) to the best of our ability, however it is
583recommended that you recompile L<DBD::Sybase> against the Sybase Open Client
584libraries. They are a part of the Sybase ASE distribution:
585
586The Open Client FAQ is here:
587L<http://www.isug.com/Sybase_FAQ/ASE/section7.html>.
588
589Sybase ASE for Linux (which comes with the Open Client libraries) may be
590downloaded here: L<http://response.sybase.com/forms/ASE_Linux_Download>.
591
592To see if you're using FreeTDS check C<< $schema->storage->using_freetds >>, or run:
593
594 perl -MDBI -le 'my $dbh = DBI->connect($dsn, $user, $pass); print $dbh->{syb_oc_version}'
595
596Some versions of the libraries involved will not support placeholders, in which
597case the storage will be reblessed to
598L<DBIx::Class::Storage::DBI::Sybase::NoBindVars>.
599
07a5866e 600In some configurations, placeholders will work but will throw implicit type
e97a6ee2 601conversion errors for anything that's not expecting a string. In such a case,
07a5866e 602the C<auto_cast> option from L<DBIx::Class::Storage::DBI::AutoCast> is
603automatically set, which you may enable on connection with
604L<DBIx::Class::Storage::DBI::AutoCast/connect_call_set_auto_cast>. The type info
605for the C<CAST>s is taken from the L<DBIx::Class::ResultSource/data_type>
606definitions in your Result classes, and are mapped to a Sybase type (if it isn't
607already) using a mapping based on L<SQL::Translator>.
e97a6ee2 608
609In other configurations, placeholers will work just as they do with the Sybase
610Open Client libraries.
611
612Inserts or updates of TEXT/IMAGE columns will B<NOT> work with FreeTDS.
613
322b7a6b 614=head1 INSERTS WITH PLACEHOLDERS
615
616With placeholders enabled, inserts are done in a transaction so that there are
617no concurrency issues with getting the inserted identity value using
618C<SELECT MAX(col)>, which is the only way to get the C<IDENTITY> value in this
619mode.
620
621When using C<DBIx::Class::Storage::DBI::Sybase::NoBindVars> transactions are
622disabled, as there are no concurrency issues with C<SELECT @@IDENTITY> as it's a
623session variable.
624
166c6561 625=head1 TRANSACTIONS
626
627Due to limitations of the TDS protocol, L<DBD::Sybase>, or both; you cannot
628begin a transaction while there are active cursors. An active cursor is, for
629example, a L<ResultSet|DBIx::Class::ResultSet> that has been executed using
630C<next> or C<first> but has not been exhausted or
75227502 631L<reset|DBIx::Class::ResultSet/reset>.
166c6561 632
322b7a6b 633For example, this will not work:
634
635 $schema->txn_do(sub {
636 my $rs = $schema->resultset('Book');
637 while (my $row = $rs->next) {
638 $schema->resultset('MetaData')->create({
639 book_id => $row->id,
640 ...
641 });
642 }
643 });
644
166c6561 645Transactions done for inserts in C<AutoCommit> mode when placeholders are in use
51ac7136 646are not affected, as they use an extra database handle to do the insert.
75227502 647
648Some workarounds:
649
650=over 4
651
75227502 652=item * use L<DBIx::Class::Storage::DBI::Replicated>
653
654=item * L<connect|DBIx::Class::Schema/connect> another L<Schema|DBIx::Class::Schema>
655
656=item * load the data from your cursor with L<DBIx::Class::ResultSet/all>
657
75227502 658=back
166c6561 659
41c93b1b 660=head1 MAXIMUM CONNECTIONS
661
e97a6ee2 662The TDS protocol makes separate connections to the server for active statements
663in the background. By default the number of such connections is limited to 25,
664on both the client side and the server side.
41c93b1b 665
e97a6ee2 666This is a bit too low for a complex L<DBIx::Class> application, so on connection
667the client side setting is set to C<256> (see L<DBD::Sybase/maxConnect>.) You
668can override it to whatever setting you like in the DSN.
41c93b1b 669
670See
671L<http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.ase_15.0.sag1/html/sag1/sag1272.htm>
672for information on changing the setting on the server side.
673
c5ce7cd6 674=head1 DATES
675
3abafb11 676See L</connect_call_datetime_setup> to setup date formats
677for L<DBIx::Class::InflateColumn::DateTime>.
c5ce7cd6 678
e97a6ee2 679=head1 TEXT/IMAGE COLUMNS
63d46bb3 680
a3a526cc 681L<DBD::Sybase> compiled with FreeTDS will B<NOT> allow you to insert or update
682C<TEXT/IMAGE> columns.
683
e97a6ee2 684Setting C<< $dbh->{LongReadLen} >> will also not work with FreeTDS use either:
685
686 $schema->storage->dbh->do("SET TEXTSIZE $bytes");
a3a526cc 687
e97a6ee2 688or
689
690 $schema->storage->set_textsize($bytes);
a3a526cc 691
692instead.
5703eb14 693
e97a6ee2 694However, the C<LongReadLen> you pass in
695L<DBIx::Class::Storage::DBI/connect_info> is used to execute the equivalent
696C<SET TEXTSIZE> command on connection.
697
63d46bb3 698See L</connect_call_blob_setup> for a L<DBIx::Class::Storage::DBI/connect_info>
699setting you need to work with C<IMAGE> columns.
700
58e3556d 701=head1 AUTHOR
3885cff6 702
7e8cecc1 703See L<DBIx::Class/CONTRIBUTORS>.
c5ce7cd6 704
3885cff6 705=head1 LICENSE
706
707You may distribute this code under the same terms as Perl itself.
708
709=cut
c5ce7cd6 710# vim:sts=2 sw=2: