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