use strict;
use warnings;
+use Class::C3;
use base qw/DBIx::Class::Storage::DBI/;
+use Carp::Clan qw/^DBIx::Class/;
+
sub _rebless {
my $self = shift;
if (!$exception && $dbtype && $self->load_optional_class($subclass)) {
bless $self, $subclass;
$self->_rebless;
- } else { # probably real Sybase
+ } else {
+ # real Sybase
if (not $self->dbh->{syb_dynamic_supported}) {
bless $self, 'DBIx::Class::Storage:DBI::Sybase::NoBindVars';
$self->_rebless;
}
+ $self->connect_call_datetime_setup;
+ $self->connect_call_blob_setup;
+ }
+ }
+}
+
+sub _populate_dbh {
+ my $self = shift;
+ $self->next::method(@_);
+ $self->connect_call_datetime_setup;
+ $self->connect_call_blob_setup;
+ 1;
+}
+
+=head2 connect_call_blob_setup
+
+Used as:
+
+ on_connect_call => 'blob_setup'
+
+Does C<< $dbh->{syb_binary_images} = 1; >> to return C<IMAGE> data as raw binary
+instead of as a hex string.
+
+Recommended.
+
+=cut
+
+sub connect_call_blob_setup {
+ my $self = shift;
+ my $dbh = $self->_dbh;
+ $dbh->{syb_binary_images} = 1;
+}
+
+=head2 connect_call_datetime_setup
+
+Used as:
+
+ on_connect_call => 'datetime_setup'
+
+In L<DBIx::Class::Storage::DBI/connect_info> to set:
+
+ $dbh->syb_date_fmt('ISO_strict'); # output fmt: 2004-08-21T14:36:48.080Z
+ $dbh->do('set dateformat mdy'); # input fmt: 08/13/1979 18:08:55.080
+
+On connection for use with L<DBIx::Class::InflateColumn::DateTime>, using
+L<DateTime::Format::Sybase>, which you will need to install.
+
+This works for both C<DATETIME> and C<SMALLDATETIME> columns, although
+C<SMALLDATETIME> columns only have minute precision.
+
+=cut
+
+{
+ my $old_dbd_warned = 0;
+
+ sub connect_call_datetime_setup {
+ my $self = shift;
+ my $dbh = $self->_dbh;
- $self->dbh->syb_date_fmt('ISO_strict');
- $self->dbh->do('set dateformat mdy');
+ if ($dbh->can('syb_date_fmt')) {
+ $dbh->syb_date_fmt('ISO_strict');
+ } elsif (not $old_dbd_warned) {
+ carp "Your DBD::Sybase is too old to support ".
+ "DBIx::Class::InflateColumn::DateTime, please upgrade!";
+ $old_dbd_warned = 1;
}
+
+ $dbh->do('set dateformat mdy');
+
+ 1;
}
}
+sub datetime_parser_type { "DateTime::Format::Sybase" }
+
sub _dbh_last_insert_id {
my ($self, $dbh, $source, $col) = @_;
- if (not $self->dbh->{syb_dynamic_supported}) {
- # @@identity works only if not using placeholders
- # Should this query be cached?
- return ($dbh->selectrow_array('select @@identity'))[0];
- }
-
# sorry, there's no other way!
my $sth = $dbh->prepare_cached("select max($col) from ".$source->from);
return ($dbh->selectrow_array($sth))[0];
}
-sub datetime_parser_type { "DBIx::Class::Storage::DBI::Sybase::DateTime" }
+=head2 count
+
+Counts for limited queries are emulated by executing select queries and
+returning the number of successful executions minus the offset.
+
+This is necessary due to the limitations of Sybase.
+
+=cut
+
+sub count {
+ my $self = shift;
+ my ($source, $attrs) = @_;
+
+ if (not exists $attrs->{rows}) {
+ return $self->next::method(@_);
+ }
+
+ my $offset = $attrs->{offset} || 0;
+ my $total = $attrs->{rows} + $offset;
+
+ my $new_attrs = $self->_copy_attributes_for_count($source, $attrs);
+
+ my $first_pk = ($source->primary_columns)[0];
+
+ $new_attrs->{select} = $first_pk ? "me.$first_pk" : 1;
+
+ my $tmp_rs = $source->resultset_class->new($source, $new_attrs);
+
+ $self->dbh->{syb_rowcount} = $total;
+
+ my $count = 0;
+ $count++ while $tmp_rs->cursor->next;
+
+ $self->dbh->{syb_rowcount} = 0;
+
+ return $count - $offset;
+}
1;
=head1 SYNOPSIS
-This subclass supports L<DBD::Sybase> for real Sybase databases. If
-you are using an MSSQL database via L<DBD::Sybase>, see
-L<DBIx::Class::Storage::DBI::Sybase::MSSQL>.
+This subclass supports L<DBD::Sybase> for real Sybase databases. If you are
+using an MSSQL database via L<DBD::Sybase>, your storage will be reblessed to
+L<DBIx::Class::Storage::DBI::Sybase::Microsoft_SQL_Server>.
-=head1 CAVEATS
+=head1 DESCRIPTION
-If your version of Sybase does not support placeholders, then this storage
-driver uses L<DBIx::Class::Storage::DBI::NoBindVars> as a base,
+If your version of Sybase does not support placeholders, then your storage
+will be reblessed to L<DBIx::Class::Storage::DBI::Sybase::NoBindVars>. You can
+also enable that driver explicitly, see the documentation for more details.
-In which case, bind variables will be interpolated (properly quoted of course)
-into the SQL query itself, without using bind placeholders.
+With this driver there is unfortunately no way to get the C<last_insert_id>
+without doing a C<select max(col)>.
-More importantly this means that caching of prepared statements is explicitly
-disabled, as the interpolation renders it useless.
+But your queries will be cached.
-If your version of Sybase B<DOES> support placeholders (check
-C<<$dbh->{syb_dynamic_supported}>> then unfortunately there's no way to get the
-C<last_insert_id> without doing a C<select max(col)>.
+A recommended L<DBIx::Class::Storage::DBI/connect_info> setting:
-But your queries will be cached.
+ on_connect_call => [qw/datetime_setup blob_setup/]
=head1 DATES
-On connection C<syb_date_fmt> is set to C<ISO_strict>, e.g.:
-C<2004-08-21T14:36:48.080Z> and C<dateformat> is set to C<mdy>, e.g.:
-C<08/13/1979>.
+See L</connect_call_datetime_setup> to setup date formats
+for L<DBIx::Class::InflateColumn::DateTime>.
-You will need the L<DateTime::Format::Strptime> module if you are going to use
-L<DBIx::Class::InflateColumn::DateTime>.
+=head1 IMAGE AND TEXT COLUMNS
-=head1 AUTHORS
+See L</connect_call_blob_setup> for a L<DBIx::Class::Storage::DBI/connect_info>
+setting you need to work with C<IMAGE> columns.
-Brandon L Black <blblack@gmail.com>
+Due to limitations in L<DBD::Sybase> and this driver, it is only possible to
+select one C<TEXT> or C<IMAGE> column at a time.
-Justin Hunter <justin.d.hunter@gmail.com>
+=head1 AUTHORS
-Rafael Kitover <rkitover@cpan.org>
+See L<DBIx::Class/CONTRIBUTORS>.
=head1 LICENSE