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