Merge 'trunk' into 'sybase'
Rafael Kitover [Wed, 3 Jun 2009 21:21:42 +0000 (21:21 +0000)]
r4349@hlagh (orig r6389):  ribasushi | 2009-05-23 13:59:17 -0700
Extra test and count fixes for prefetch + distinct
r4350@hlagh (orig r6390):  caelum | 2009-05-23 14:04:01 -0700
minor clean up
r4351@hlagh (orig r6391):  ribasushi | 2009-05-23 14:37:19 -0700
Make sure MultiColumnIn quotes column names while munging literal sql
Tested by running t/resultset/update_delete against pg with quote char " and name sep .
r4352@hlagh (orig r6392):  ribasushi | 2009-05-23 15:47:40 -0700
update changes
r4353@hlagh (orig r6393):  ribasushi | 2009-05-23 15:50:08 -0700
Extend distinct deprecation tests and clarify warnings
r4355@hlagh (orig r6395):  ribasushi | 2009-05-24 01:47:03 -0700
MSSQL through ODBC does not like unfinished statements - make sure we finish the scope identity retrieval
(This worked before because of the automatic retry on exception, essentially running any select after insert twice)
r4356@hlagh (orig r6396):  ribasushi | 2009-05-24 02:42:01 -0700
Make sure we do not clobber search attributes when using subqueries
r4357@hlagh (orig r6397):  ribasushi | 2009-05-24 02:43:32 -0700
SUPER is so last century
r4358@hlagh (orig r6398):  ribasushi | 2009-05-24 05:12:39 -0700
Deprecate ::DBI::Sybase::MSSQL
r4359@hlagh (orig r6399):  ribasushi | 2009-05-24 06:00:50 -0700
eol adjustments
r4360@hlagh (orig r6400):  ribasushi | 2009-05-24 06:07:45 -0700
Switch trunk to native eol-style
r4361@hlagh (orig r6401):  ribasushi | 2009-05-24 06:35:07 -0700
Failing test about warnings triggered in SQLA::Limit when using a subquery
r4365@hlagh (orig r6405):  ribasushi | 2009-05-24 13:53:15 -0700
Switch around inheritance of MSSQL drivers, remove some duplicate code
r4366@hlagh (orig r6406):  caelum | 2009-05-24 16:49:17 -0700
fix double connect for ODBC/MSSQL
r4367@hlagh (orig r6407):  caelum | 2009-05-24 16:53:12 -0700
added test to make sure only one connection to ODBC/MSSQL is made
r4520@hlagh (orig r6410):  ribasushi | 2009-05-24 23:48:38 -0700
Factor out the order_by sqlahacks resolver
r4521@hlagh (orig r6411):  ribasushi | 2009-05-25 00:42:45 -0700
Move the DB2 Limit syntax setting into the storage class
r4522@hlagh (orig r6412):  ribasushi | 2009-05-25 00:47:01 -0700
Forgotten podcoverage override
r4523@hlagh (orig r6413):  ribasushi | 2009-05-25 02:11:01 -0700
Define how Top limit emulation should behave
r5249@hlagh (orig r6418):  ribasushi | 2009-05-25 07:53:13 -0700
Actually don't need this anymore
r5251@hlagh (orig r6420):  tomboh | 2009-05-25 09:33:46 -0700
Small documentation improvement:  link to a documented method.
r5253@hlagh (orig r6422):  ribasushi | 2009-05-25 10:42:02 -0700
This method does not exist anymore
r5254@hlagh (orig r6426):  ribasushi | 2009-05-25 23:15:34 -0700
TODOified test for RT#40701
r5256@hlagh (orig r6428):  ash | 2009-05-26 07:17:44 -0700
Fix 'timestamp with time zone' columns for IC::DT inflation

r5258@hlagh (orig r6430):  ribasushi | 2009-05-26 07:29:55 -0700
 r6415@Thesaurus (orig r6414):  ribasushi | 2009-05-25 11:18:05 +0200
 Yet another branch to attempt a top fix
 r6416@Thesaurus (orig r6415):  ribasushi | 2009-05-25 11:24:32 +0200
 The Top limit emulation bundled with SQLA::Limit assumes that the limited resultset will be _always_ sorted. In order to fix this, I reimplemented _Top in SQLAHacks with a slight modification. Now the original order_by is passed to the outside of the nested select block, while order_up/down are calculated either based on the original order_by, or if one is not present an order by all PKs is attempted.
 Since I do not have access to $rsrc in SQLA, I pass the list of PKs as an extra group_by hash entry. This appears to be rather safe, and besides we already pollute order_by with group_by and having (which seems to work rather well).
 The only thing I am unsure about is the need for _gen_virtual_order(). Initially I was going to generate the pk list, only if we use the Top limit. Then it turned out there is no limit dialect before we connect, so I commented it out. Now all it does is check for a limit condition and returns the PK list. Is this necessary at all?
 r6417@Thesaurus (orig r6416):  ribasushi | 2009-05-25 16:08:40 +0200
 Shoot another Top problem, move test from top_limit_tweaks branch and delete
 r6420@Thesaurus (orig r6419):  ribasushi | 2009-05-25 17:45:33 +0200
 Too much logic for no benefit - always populate _virtual_order_by

r5260@hlagh (orig r6432):  ribasushi | 2009-05-26 07:36:55 -0700
Fix test skip message
r5261@hlagh (orig r6433):  ribasushi | 2009-05-26 08:20:57 -0700
Minor fixes of the return value of rs->update/delete
r5262@hlagh (orig r6434):  ribasushi | 2009-05-26 11:49:49 -0700
fix comments
r5263@hlagh (orig r6435):  ribasushi | 2009-05-26 12:28:49 -0700
Attempt to reproduce reported mysql error (failed) - fixed another bug in ResultSetColumn along the way
r5264@hlagh (orig r6436):  ribasushi | 2009-05-26 13:02:29 -0700
Release 0.08103
r5288@hlagh (orig r6446):  ribasushi | 2009-05-28 01:20:57 -0700
Commit rather useless but already written mysql test extension
r5289@hlagh (orig r6447):  ribasushi | 2009-05-28 04:02:22 -0700
Fix multiprefetch warning - we can now count properly
r5290@hlagh (orig r6456):  ribasushi | 2009-05-29 22:40:24 -0700
Patch + test for more informative exceptions on load_namespace a non-rs class
r5291@hlagh (orig r6457):  ribasushi | 2009-05-30 00:34:20 -0700
Add better error reporting on bulk_insert (ash++)
r5300@hlagh (orig r6469):  ribasushi | 2009-05-30 10:46:09 -0700
populate() fix and Changes
r5301@hlagh (orig r6470):  ribasushi | 2009-05-31 00:37:37 -0700
M::I 0.89 finally resolves all provlems with auto_install
r5302@hlagh (orig r6471):  ribasushi | 2009-05-31 00:42:35 -0700
Throw away the makefile SQLite test - it served its purpose
r5303@hlagh (orig r6472):  ribasushi | 2009-05-31 02:24:15 -0700
There is a saner way to write out resources
r5304@hlagh (orig r6473):  ribasushi | 2009-05-31 07:07:18 -0700
Last set of Makefile.PL optimizations
r5305@hlagh (orig r6474):  ribasushi | 2009-06-01 03:24:41 -0700
deploy-related pod fixes
r5307@hlagh (orig r6476):  ribasushi | 2009-06-01 07:40:22 -0700
 r6462@Thesaurus (orig r6461):  mo | 2009-05-30 11:06:54 +0200
 order_by tests

r5308@hlagh (orig r6477):  ribasushi | 2009-06-01 07:40:30 -0700
 r6463@Thesaurus (orig r6462):  ribasushi | 2009-05-30 16:54:37 +0200
 TODOify some of the order with bind tests

r5309@hlagh (orig r6478):  ribasushi | 2009-06-01 07:40:41 -0700
 r6464@Thesaurus (orig r6463):  ribasushi | 2009-05-30 16:55:37 +0200
 Restructure bind tests

r5310@hlagh (orig r6479):  ribasushi | 2009-06-01 07:40:50 -0700
 r6465@Thesaurus (orig r6464):  ribasushi | 2009-05-30 17:15:57 +0200
 Greatly simplify _order_by override to fallback on new SQLA

r5311@hlagh (orig r6480):  ribasushi | 2009-06-01 07:40:56 -0700
 r6467@Thesaurus (orig r6466):  ribasushi | 2009-05-30 19:13:23 +0200
 Evil hack to make Carp::Clan work throughout SQLA as well

r5312@hlagh (orig r6481):  ribasushi | 2009-06-01 07:41:42 -0700
 r6468@Thesaurus (orig r6467):  ribasushi | 2009-05-30 19:17:02 +0200
 Add changes

r5313@hlagh (orig r6482):  ribasushi | 2009-06-01 07:41:49 -0700

r5315@hlagh (orig r6484):  ribasushi | 2009-06-01 07:49:09 -0700
Fix fallout from another botched merge (I suck, part 2)
r5317@hlagh (orig r6486):  ribasushi | 2009-06-03 01:14:51 -0700
Require a recent version of Date::Simple during CDBI tests

Makefile.PL
lib/DBIx/Class/Storage/DBI/Sybase.pm
lib/DBIx/Class/Storage/DBI/Sybase/DateTime.pm [new file with mode: 0644]
lib/DBIx/Class/Storage/DBI/Sybase/Microsoft_SQL_Server.pm
lib/DBIx/Class/Storage/DBI/Sybase/NoBindVars.pm [new file with mode: 0644]
t/746sybase.t
t/lib/DBICNSTest/Bogus/B.pm [new file with mode: 0644]

index d8225bc..80de580 100644 (file)
@@ -92,6 +92,7 @@ my %force_requires_if_author = (
   'Hash::Merge',                  => 0.11,
 
   # t/96_is_deteministic_value.t
+  # t/746sybase.t
   'DateTime::Format::Strptime' => 0,
 );
 
index ec4fcf7..28b4059 100644 (file)
@@ -3,27 +3,51 @@ package DBIx::Class::Storage::DBI::Sybase;
 use strict;
 use warnings;
 
-use base qw/DBIx::Class::Storage::DBI::NoBindVars/;
+use base qw/DBIx::Class::Storage::DBI/;
 
 sub _rebless {
-    my $self = shift;
-
-    my $dbtype = eval { @{$self->dbh->selectrow_arrayref(qq{sp_server_info \@attribute_id=1})}[2] };
-    unless ( $@ ) {
-        $dbtype =~ s/\W/_/gi;
-        my $subclass = "DBIx::Class::Storage::DBI::Sybase::${dbtype}";
-        if ($self->load_optional_class($subclass) && !$self->isa($subclass)) {
-            bless $self, $subclass;
-            $self->_rebless;
-        }
+  my $self = shift;
+
+  if (ref($self) eq 'DBIx::Class::Storage::DBI::Sybase') {
+    my $dbtype = eval {
+      @{$self->dbh->selectrow_arrayref(qq{sp_server_info \@attribute_id=1})}[2]
+    } || '';
+
+    my $exception = $@;
+    $dbtype =~ s/\W/_/gi;
+    my $subclass = "DBIx::Class::Storage::DBI::Sybase::${dbtype}";
+
+    if (!$exception && $dbtype && $self->load_optional_class($subclass)) {
+      bless $self, $subclass;
+      $self->_rebless;
+    } else { # probably real Sybase
+      if (not $self->dbh->{syb_dynamic_supported}) {
+        bless $self, 'DBIx::Class::Storage:DBI::Sybase::NoBindVars';
+        $self->_rebless;
+      }
+
+      $self->dbh->syb_date_fmt('ISO_strict');
+      $self->dbh->do('set dateformat mdy');
     }
+  }
 }
 
 sub _dbh_last_insert_id {
-    my ($self, $dbh, $source, $col) = @_;
+  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" }
+
 1;
 
 =head1 NAME
@@ -38,21 +62,41 @@ L<DBIx::Class::Storage::DBI::Sybase::MSSQL>.
 
 =head1 CAVEATS
 
-This storage driver uses L<DBIx::Class::Storage::DBI::NoBindVars> as a base.
-This means that bind variables will be interpolated (properly quoted of course)
+If your version of Sybase does not support placeholders, then this storage
+driver uses L<DBIx::Class::Storage::DBI::NoBindVars> as a base,
+
+In which case, bind variables will be interpolated (properly quoted of course)
 into the SQL query itself, without using bind placeholders.
 
 More importantly this means that caching of prepared statements is explicitly
 disabled, as the interpolation renders it useless.
 
+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)>.
+
+But your queries will be cached.
+
+=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>.
+
+You will need the L<DateTime::Format::Strptime> module if you are going to use
+L<DBIx::Class::InflateColumn::DateTime>.
+
 =head1 AUTHORS
 
 Brandon L Black <blblack@gmail.com>
 
 Justin Hunter <justin.d.hunter@gmail.com>
 
+Rafael Kitover <rkitover@cpan.org>
+
 =head1 LICENSE
 
 You may distribute this code under the same terms as Perl itself.
 
 =cut
+# vim:sts=2 sw=2:
diff --git a/lib/DBIx/Class/Storage/DBI/Sybase/DateTime.pm b/lib/DBIx/Class/Storage/DBI/Sybase/DateTime.pm
new file mode 100644 (file)
index 0000000..37609ee
--- /dev/null
@@ -0,0 +1,20 @@
+package # hide from PAUSE
+    DBIx::Class::Storage::DBI::Sybase::DateTime;
+
+use strict;
+use warnings;
+use DateTime::Format::Strptime;
+
+my $inflate_format = DateTime::Format::Strptime->new(
+    pattern => '%Y-%m-%dT%H:%M:%S.%3NZ'
+);
+
+my $deflate_format = DateTime::Format::Strptime->new(
+    pattern => '%m/%d/%Y %H:%M:%S.%3N'
+);
+
+sub parse_datetime  { shift; $inflate_format->parse_datetime(@_) }
+
+sub format_datetime { shift; $deflate_format->format_datetime(@_) }
+
+1;
index 58ac36f..35171e2 100644 (file)
@@ -6,6 +6,7 @@ use warnings;
 use base qw/
   DBIx::Class::Storage::DBI::ODBC::Microsoft_SQL_Server
   DBIx::Class::Storage::DBI::Sybase
+  DBIx::Class::Storage::DBI::NoBindVars
 /;
 
 1;
diff --git a/lib/DBIx/Class/Storage/DBI/Sybase/NoBindVars.pm b/lib/DBIx/Class/Storage/DBI/Sybase/NoBindVars.pm
new file mode 100644 (file)
index 0000000..72a7372
--- /dev/null
@@ -0,0 +1,9 @@
+package # hide from PAUSE
+    DBIx::Class::Storage::DBI::Sybase::NoBindVars;
+
+use base qw/
+  DBIx::Class::Storage::DBI::NoBindVars
+  DBIx::Class::Storage::DBI::Sybase
+/;
+
+1;
index f09862f..035091f 100644 (file)
@@ -4,13 +4,14 @@ use warnings;
 use Test::More;
 use lib qw(t/lib);
 use DBICTest;
+use DBIx::Class::Storage::DBI::Sybase::DateTime;
 
 my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_SYBASE_${_}" } qw/DSN USER PASS/};
 
 plan skip_all => 'Set $ENV{DBICTEST_SYBASE_DSN}, _USER and _PASS to run this test'
   unless ($dsn && $user);
 
-plan tests => 12;
+plan tests => 15;
 
 my $schema = DBICTest::Schema->connect($dsn, $user, $pass, {AutoCommit => 1});
 
@@ -20,16 +21,24 @@ isa_ok( $schema->storage, 'DBIx::Class::Storage::DBI::Sybase' );
 $schema->storage->dbh_do (sub {
     my ($storage, $dbh) = @_;
     eval { $dbh->do("DROP TABLE artist") };
+    eval { $dbh->do("DROP TABLE track") };
     $dbh->do(<<'SQL');
-
 CREATE TABLE artist (
-   artistid INT IDENTITY NOT NULL,
+   artistid INT IDENTITY PRIMARY KEY,
    name VARCHAR(100),
    rank INT DEFAULT 13 NOT NULL,
-   charfield CHAR(10) NULL,
-   primary key(artistid)
+   charfield CHAR(10) NULL
 )
+SQL
 
+# we only need the DT
+    $dbh->do(<<'SQL');
+CREATE TABLE track (
+   trackid INT IDENTITY PRIMARY KEY,
+   cd INT,
+   position INT,
+   last_updated_on DATETIME,
+)
 SQL
 
 });
@@ -52,9 +61,7 @@ for (1..6) {
     $seen_id{$new->artistid}++;
 }
 
-my $it;
-
-$it = $schema->resultset('Artist')->search( {}, {
+my $it = $schema->resultset('Artist')->search( {}, {
     rows => 3,
     order_by => 'artistid',
 });
@@ -73,10 +80,26 @@ $it->next;
 is( $it->next->name, "Artist 2", "iterator->next ok" );
 is( $it->next, undef, "next past end of resultset ok" );
 
+# Test DateTime inflation
+
+my $dt = DBIx::Class::Storage::DBI::Sybase::DateTime
+    ->parse_datetime('2004-08-21T14:36:48.080Z');
+
+my $row;
+ok( $row = $schema->resultset('Track')->create({
+    last_updated_on => $dt,
+    cd => 1,
+}));
+ok( $row = $schema->resultset('Track')
+    ->search({ trackid => $row->trackid }, { select => ['last_updated_on'] })
+    ->first
+);
+is( $row->updated_date, $dt, 'DateTime inflation works' );
 
 # clean up our mess
 END {
-    my $dbh = eval { $schema->storage->_dbh };
-    $dbh->do('DROP TABLE artist') if $dbh;
+    if (my $dbh = eval { $schema->storage->_dbh }) {
+        $dbh->do('DROP TABLE artist');
+        $dbh->do('DROP TABLE track');
+    }
 }
-
diff --git a/t/lib/DBICNSTest/Bogus/B.pm b/t/lib/DBICNSTest/Bogus/B.pm
new file mode 100644 (file)
index 0000000..e9cdc37
--- /dev/null
@@ -0,0 +1,6 @@
+package DBICNSTest::Result::B;
+use base qw/DBIx::Class/;
+__PACKAGE__->load_components(qw/PK::Auto Core/);
+__PACKAGE__->table('b');
+__PACKAGE__->add_columns('b');
+1;