Drop-in legacy code for DB2-AS/400
Peter Rabbitson [Sat, 14 Aug 2010 11:04:14 +0000 (13:04 +0200)]
lib/DBIx/Class/SQLAHacks/LimitDialects.pm
lib/DBIx/Class/Storage/DBI/ODBC/DB2_400_SQL.pm

index 1cf5cb7..2ca6fd5 100644 (file)
@@ -7,6 +7,78 @@ use Carp::Clan qw/^DBIx::Class|^SQL::Abstract|^Try::Tiny/;
 use List::Util 'first';
 use namespace::clean;
 
+# FIXME
+# This dialect has not been ported to the subquery-realiasing code
+# that all other subquerying dialects are using. It is very possible
+# that this dialect is entirely unnecessary - it is currently only
+# used by ::Storage::DBI::ODBC::DB2_400_SQL which *should* be able to
+# just subclass ::Storage::DBI::DB2 and use the already rewritten
+# RowNumberOver. However nobody has access to this specific database
+# engine, thus keeping legacy code as-is
+# IF someone ever manages to test DB2-AS/400 with RNO, all the code
+# in this block should go on to meet its maker
+{
+  sub _FetchFirst {
+    my ( $self, $sql, $order, $rows, $offset ) = @_;
+
+    my $last = $rows + $offset;
+
+    my ( $order_by_up, $order_by_down ) = $self->_order_directions( $order );
+
+    $sql = "
+      SELECT * FROM (
+        SELECT * FROM (
+          $sql
+          $order_by_up
+          FETCH FIRST $last ROWS ONLY
+        ) foo
+        $order_by_down
+        FETCH FIRST $rows ROWS ONLY
+      ) bar
+      $order_by_up
+    ";
+
+    return $sql;
+  }
+
+  sub _order_directions {
+    my ( $self, $order ) = @_;
+
+    return unless $order;
+
+    my $ref = ref $order;
+
+    my @order;
+
+    CASE: {
+      @order = @$order,     last CASE if $ref eq 'ARRAY';
+      @order = ( $order ),  last CASE unless $ref;
+      @order = ( $$order ), last CASE if $ref eq 'SCALAR';
+      croak __PACKAGE__ . ": Unsupported data struct $ref for ORDER BY";
+    }
+
+    my ( $order_by_up, $order_by_down );
+
+    foreach my $spec ( @order )
+    {
+        my @spec = split ' ', $spec;
+        croak( "bad column order spec: $spec" ) if @spec > 2;
+        push( @spec, 'ASC' ) unless @spec == 2;
+        my ( $col, $up ) = @spec; # or maybe down
+        $up = uc( $up );
+        croak( "bad direction: $up" ) unless $up =~ /^(?:ASC|DESC)$/;
+        $order_by_up .= ", $col $up";
+        my $down = $up eq 'ASC' ? 'DESC' : 'ASC';
+        $order_by_down .= ", $col $down";
+    }
+
+    s/^,/ORDER BY/ for ( $order_by_up, $order_by_down );
+
+    return $order_by_up, $order_by_down;
+  }
+}
+### end-of-FIXME
+
 # PostgreSQL and SQLite
 sub _LimitOffset {
     my ( $self, $sql, $order, $rows, $offset ) = @_;
index 16be2f8..29e9da9 100644 (file)
@@ -5,6 +5,21 @@ use warnings;
 use base qw/DBIx::Class::Storage::DBI::ODBC/;
 use mro 'c3';
 
+warn 'Major advances took place in the DBIC codebase since this driver'
+  .' (::Storage::DBI::ODBC::DB2_400_SQL) was written. However since the'
+  .' RDBMS in question is so rare it is not possible for us to test any'
+  .' of the "new hottness". If you are using DB2 on AS-400 please get'
+  .' in contact with the developer team:'
+  .' http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class.pm#GETTING_HELP/SUPPORT'
+  ."\n"
+;
+
+# FIXME
+# Most likely all of this code is redundant and unnecessary. We should
+# be able to simply use base qw/DBIx::Class::Storage::DBI::DB2/;
+# Unfortunately nobody has an RDBMS engine to test with, so keeping
+# things as-is for the time being
+
 sub _dbh_last_insert_id {
     my ($self, $dbh, $source, $col) = @_;