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