1 package DBIx::Class::Storage::DBI::Sybase;
7 DBIx::Class::Storage::DBI::Sybase::Base
8 DBIx::Class::Storage::DBI
11 use Carp::Clan qw/^DBIx::Class/;
14 __PACKAGE__->mk_group_accessors('simple' =>
15 qw/_identity _blob_log_on_update/
20 DBIx::Class::Storage::DBI::Sybase - Sybase support for DBIx::Class
24 This subclass supports L<DBD::Sybase> for real Sybase databases. If you are
25 using an MSSQL database via L<DBD::Sybase>, your storage will be reblessed to
26 L<DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server>.
30 If your version of Sybase does not support placeholders, then your storage
31 will be reblessed to L<DBIx::Class::Storage::DBI::Sybase::NoBindVars>. You can
32 also enable that driver explicitly, see the documentation for more details.
34 With this driver there is unfortunately no way to get the C<last_insert_id>
35 without doing a C<SELECT MAX(col)>.
37 But your queries will be cached.
39 You need a version of L<DBD::Sybase> compiled with the Sybase OpenClient
40 libraries, B<NOT> FreeTDS, for placeholder support. Otherwise your storage will
41 be automatically reblessed into C<::NoBindVars>.
43 A recommended L<DBIx::Class::Storage::DBI/connect_info> setting:
45 on_connect_call => [['datetime_setup'], ['blob_setup', log_on_update => 0]]
54 if (ref($self) eq 'DBIx::Class::Storage::DBI::Sybase') {
56 @{$self->dbh->selectrow_arrayref(qq{sp_server_info \@attribute_id=1})}[2]
61 my $subclass = "DBIx::Class::Storage::DBI::Sybase::${dbtype}";
63 if (!$exception && $dbtype && $self->load_optional_class($subclass)) {
64 bless $self, $subclass;
66 } else { # real Sybase
67 my $no_bind_vars = 'DBIx::Class::Storage::DBI::Sybase::NoBindVars';
69 if ($self->_using_freetds) {
72 Your version of Sybase potentially supports placeholders and query caching,
73 however you seem to be using FreeTDS which does not (yet?) support this.
75 Please recompile DBD::Sybase with the Sybase OpenClient libraries if you want
78 TEXT/IMAGE column support will also not work under FreeTDS.
80 See perldoc DBIx::Class::Storage::DBI::Sybase for more details.
82 $self->ensure_class_loaded($no_bind_vars);
83 bless $self, $no_bind_vars;
87 if (not $self->dbh->{syb_dynamic_supported}) {
88 $self->ensure_class_loaded($no_bind_vars);
89 bless $self, $no_bind_vars;
93 $self->_set_maxConnect;
98 # Make sure we have CHAINED mode turned on, we don't know how DBD::Sybase was
102 $self->next::method(@_);
103 $self->_dbh->{syb_chained_txn} = 1;
109 return $self->_dbh->{syb_oc_version} =~ /freetds/i;
112 sub _set_maxConnect {
115 my $dsn = $self->_dbi_connect_info->[0];
117 return if ref($dsn) eq 'CODE';
119 if ($dsn !~ /maxConnect=/) {
120 $self->_dbi_connect_info->[0] = "$dsn;maxConnect=256";
121 my $connected = defined $self->_dbh;
123 $self->ensure_connected if $connected;
127 =head2 connect_call_blob_setup
131 on_connect_call => [ [ 'blob_setup', log_on_update => 0 ] ]
133 Does C<< $dbh->{syb_binary_images} = 1; >> to return C<IMAGE> data as raw binary
134 instead of as a hex string.
138 Also sets the C<log_on_update> value for blob write operations. The default is
139 C<1>, but C<0> is better if your database is configured for it.
142 L<DBD::Sybase/Handling_IMAGE/TEXT_data_with_syb_ct_get_data()/syb_ct_send_data()>.
146 sub connect_call_blob_setup {
149 my $dbh = $self->_dbh;
150 $dbh->{syb_binary_images} = 1;
152 $self->_blob_log_on_update($args{log_on_update})
153 if exists $args{log_on_update};
159 $type && $type =~ /(?:text|image|lob|bytea|binary|memo)/i;
162 ## This will be useful if we ever implement BLOB filehandle inflation and will
163 ## need to use the API, but for now it isn't.
165 #sub order_columns_for_select {
166 # my ($self, $source, $columns) = @_;
168 # my (@non_blobs, @blobs);
170 # for my $col (@$columns) {
171 # if ($self->_is_lob_type($source->column_info($col)->{data_type})) {
174 # push @non_blobs, $col;
178 # croak "cannot select more than a one TEXT/IMAGE column at a time"
181 # return (@non_blobs, @blobs);
184 # the select-piggybacking-on-insert trick stolen from odbc/mssql
185 sub _prep_for_execute {
187 my ($op, $extra_bind, $ident, $args) = @_;
189 my ($sql, $bind) = $self->next::method (@_);
191 if ($op eq 'insert') {
192 my $table = $ident->from;
194 my $bind_info = $self->_resolve_column_info($ident, [map $_->[0], @{$bind}]);
196 List::Util::first { $bind_info->{$_}{is_auto_increment} } (keys %$bind_info);
200 "SET IDENTITY_INSERT $table ON\n" .
202 "SET IDENTITY_INSERT $table OFF"
204 $identity_col = List::Util::first {
205 $ident->column_info($_)->{is_auto_increment}
212 $self->_fetch_identity_sql($ident, $identity_col) . "\n";
216 return ($sql, $bind);
219 sub _fetch_identity_sql {
220 my ($self, $source, $col) = @_;
222 return "SELECT MAX($col) FROM ".$source->from;
229 my ($rv, $sth, @bind) = $self->dbh_do($self->can('_dbh_execute'), @_);
231 if ($op eq 'insert') {
232 $self->_identity($sth->fetchrow_array);
236 return wantarray ? ($rv, $sth, @bind) : $rv;
239 sub last_insert_id { shift->_identity }
241 # override to handle TEXT/IMAGE and nested txn
243 my ($self, $source, $to_insert) = splice @_, 0, 3;
244 my $dbh = $self->_dbh;
246 my $blob_cols = $self->_remove_blob_cols($source, $to_insert);
248 # Sybase has nested transactions fortunately, because we have to do the insert
249 # in a transaction to avoid race conditions with the SELECT MAX(COL) identity
250 # method used when placeholders are enabled.
251 my $updated_cols = do {
252 local $self->{auto_savepoint} = 1;
254 my $method = $self->next::can;
256 sub { $self->$method($source, $to_insert, @$args) }
260 $self->_insert_blobs($source, $blob_cols, $to_insert) if %$blob_cols;
262 return $updated_cols;
266 my ($self, $source) = splice @_, 0, 2;
267 my ($fields, $where) = @_;
268 my $wantarray = wantarray;
270 my $blob_cols = $self->_remove_blob_cols($source, $fields);
274 @res = $self->next::method($source, @_);
276 $res[0] = $self->next::method($source, @_);
279 $self->_update_blobs($source, $blob_cols, $where) if %$blob_cols;
281 return $wantarray ? @res : $res[0];
284 sub _remove_blob_cols {
285 my ($self, $source, $fields) = @_;
289 for my $col (keys %$fields) {
290 if ($self->_is_lob_type($source->column_info($col)->{data_type})) {
291 $blob_cols{$col} = delete $fields->{$col};
292 $fields->{$col} = \"''";
300 my ($self, $source, $blob_cols, $where) = @_;
302 my (@primary_cols) = $source->primary_columns;
304 croak "Cannot update TEXT/IMAGE column(s) without a primary key"
305 unless @primary_cols;
307 # check if we're updating a single row by PK
308 my $pk_cols_in_where = 0;
309 for my $col (@primary_cols) {
310 $pk_cols_in_where++ if defined $where->{$col};
314 if ($pk_cols_in_where == @primary_cols) {
316 @row_to_update{@primary_cols} = @{$where}{@primary_cols};
317 @rows = \%row_to_update;
319 my $rs = $source->resultset->search(
322 result_class => 'DBIx::Class::ResultClass::HashRefInflator',
323 select => \@primary_cols
326 @rows = $rs->all; # statement must finish
329 for my $row (@rows) {
330 $self->_insert_blobs($source, $blob_cols, $row);
335 my ($self, $source, $blob_cols, $row) = @_;
336 my $dbh = $self->dbh;
338 my $table = $source->from;
341 my (@primary_cols) = $source->primary_columns;
343 croak "Cannot update TEXT/IMAGE column(s) without a primary key"
344 unless @primary_cols;
346 if ((grep { defined $row{$_} } @primary_cols) != @primary_cols) {
347 if (@primary_cols == 1) {
348 my $col = $primary_cols[0];
349 $row{$col} = $self->last_insert_id($source, $col);
351 croak "Cannot update TEXT/IMAGE column(s) without primary key values";
355 for my $col (keys %$blob_cols) {
356 my $blob = $blob_cols->{$col};
359 if (not $self->isa('DBIx::Class::Storage::DBI::NoBindVars')) {
360 my $search_cond = join ',' => map "$_ = ?", @primary_cols;
363 "select $col from $table where $search_cond"
365 $sth->execute(map $row{$_}, @primary_cols);
367 my $search_cond = join ',' => map "$_ = $row{$_}", @primary_cols;
369 $sth = $dbh->prepare(
370 "select $col from $table where $search_cond"
376 while ($sth->fetch) {
377 $sth->func('CS_GET', 1, 'ct_data_info') or die $sth->errstr;
379 $sth->func('ct_prepare_send') or die $sth->errstr;
381 my $log_on_update = $self->_blob_log_on_update;
382 $log_on_update = 1 if not defined $log_on_update;
384 $sth->func('CS_SET', 1, {
385 total_txtlen => length($blob),
386 log_on_update => $log_on_update
387 }, 'ct_data_info') or die $sth->errstr;
389 $sth->func($blob, length($blob), 'ct_send_data') or die $sth->errstr;
391 $sth->func('ct_finish_send') or die $sth->errstr;
395 croak $exception if $exception;
399 =head2 connect_call_datetime_setup
403 on_connect_call => 'datetime_setup'
405 In L<DBIx::Class::Storage::DBI/connect_info> to set:
407 $dbh->syb_date_fmt('ISO_strict'); # output fmt: 2004-08-21T14:36:48.080Z
408 $dbh->do('set dateformat mdy'); # input fmt: 08/13/1979 18:08:55.080
410 On connection for use with L<DBIx::Class::InflateColumn::DateTime>, using
411 L<DateTime::Format::Sybase>, which you will need to install.
413 This works for both C<DATETIME> and C<SMALLDATETIME> columns, although
414 C<SMALLDATETIME> columns only have minute precision.
419 my $old_dbd_warned = 0;
421 sub connect_call_datetime_setup {
423 my $dbh = $self->_dbh;
425 if ($dbh->can('syb_date_fmt')) {
426 $dbh->syb_date_fmt('ISO_strict');
427 } elsif (not $old_dbd_warned) {
428 carp "Your DBD::Sybase is too old to support ".
429 "DBIx::Class::InflateColumn::DateTime, please upgrade!";
433 $dbh->do('set dateformat mdy');
439 sub datetime_parser_type { "DateTime::Format::Sybase" }
441 # savepoint support using ASE syntax
444 my ($self, $name) = @_;
446 $self->dbh->do("SAVE TRANSACTION $name");
449 # A new SAVE TRANSACTION with the same name releases the previous one.
450 sub _svp_release { 1 }
453 my ($self, $name) = @_;
455 $self->dbh->do("ROLLBACK TRANSACTION $name");
460 =head1 MAXIMUM CONNECTIONS
462 L<DBD::Sybase> makes separate connections to the server for active statements in
463 the background. By default the number of such connections is limited to 25, on
464 both the client side and the server side.
466 This is a bit too low, so on connection the clientside setting is set to C<256>
467 (see L<DBD::Sybase/maxConnect>.) You can override it to whatever setting you
471 L<http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.ase_15.0.sag1/html/sag1/sag1272.htm>
472 for information on changing the setting on the server side.
476 See L</connect_call_datetime_setup> to setup date formats
477 for L<DBIx::Class::InflateColumn::DateTime>.
479 =head1 IMAGE AND TEXT COLUMNS
481 L<DBD::Sybase> compiled with FreeTDS will B<NOT> work with C<TEXT/IMAGE>
484 See L</connect_call_blob_setup> for a L<DBIx::Class::Storage::DBI/connect_info>
485 setting you need to work with C<IMAGE> columns.
489 See L<DBIx::Class/CONTRIBUTORS>.
493 You may distribute this code under the same terms as Perl itself.