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