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