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