[Dbix-class] Resurrected select for patch

Matt S Trout dbix-class at trout.me.uk
Mon Sep 24 19:26:32 GMT 2007


(sorry for the top-posting everybody)

Can somebody with a pg test rig already set up verify this and commit it
please?

On Mon, Sep 24, 2007 at 01:42:16AM -0400, Justin DeVuyst wrote:
> Attached you should find a working version of a patch originally by
> Daisuke Maki.  I had to modify it so it works, again.  I'm presuming
> it did work when Daisuke whipped it up back in July...  The original
> is here: 
> http://lists.scsys.co.uk/pipermail/dbix-class/2007-July/004577.html. 
> I wasn't able to test the Oracle change since I don't have Oracle.  I
> did test the Pg portion and it all passed.
> 
> jdv
> Index: t/72pg.t
> ===================================================================
> --- t/72pg.t	(revision 3567)
> +++ t/72pg.t	(working copy)
> @@ -27,7 +27,7 @@
>  plan skip_all => 'Set $ENV{DBICTEST_PG_DSN}, _USER and _PASS to run this test'
>   . ' (note: creates and drops tables named artist and casecheck!)' unless ($dsn && $user);
>  
> -plan tests => 10;
> +plan tests => 16;
>  
>  DBICTest::Schema->load_classes( 'Casecheck' );
>  my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
> @@ -87,6 +87,83 @@
>  my $uc_name_info = $schema->source('Casecheck')->column_info( 'uc_name' );
>  is( $uc_name_info->{size}, 3, "Case insensitive matching info for 'uc_name'" );
>  
> +# Test SELECT ... FOR UPDATE
> +my $HaveSysSigAction = eval "require Sys::SigAction" && !$@;
> +if ($HaveSysSigAction) {
> +    Sys::SigAction->import( 'set_sig_handler' );
> +}
> +
> +SKIP: {
> +    skip "Sys::SigAction is not available", 3 unless $HaveSysSigAction;
> +    # create a new schema
> +    my $schema2 = DBICTest::Schema->connect($dsn, $user, $pass);
> +    $schema2->source("Artist")->name("testschema.artist");
> +
> +    $schema->txn_do( sub {
> +        my $artist = $schema->resultset('Artist')->search(
> +            {
> +                artistid => 1
> +            },
> +            {
> +                for => 'update'
> +            }
> +        )->first;
> +        is($artist->artistid, 1, "select for update returns artistid = 1");
> +
> +        my $artist_from_schema2;
> +        my $error_ok = 0;
> +        eval {
> +            my $h = set_sig_handler( 'ALRM', sub { die "DBICTestTimeout" } );
> +            alarm(2);
> +            $artist_from_schema2 = $schema2->resultset('Artist')->find(1);
> +            $artist_from_schema2->name('fooey');
> +            $artist_from_schema2->update;
> +            alarm(0);
> +        };
> +        if (my $e = $@) {
> +            $error_ok = $e =~ /DBICTestTimeout/;
> +        }
> +
> +        # Make sure that an error was raised, and that the update failed
> +        ok($error_ok, "update from second schema times out");
> +        ok($artist_from_schema2->is_column_changed('name'), "'name' column is still dirty from second schema");
> +    });
> +}
> +
> +SKIP: {
> +    skip "Sys::SigAction is not available", 3 unless $HaveSysSigAction;
> +    # create a new schema
> +    my $schema2 = DBICTest::Schema->connect($dsn, $user, $pass);
> +    $schema2->source("Artist")->name("testschema.artist");
> +
> +    $schema->txn_do( sub {
> +        my $artist = $schema->resultset('Artist')->search(
> +            {
> +                artistid => 1
> +            },
> +        )->first;
> +        is($artist->artistid, 1, "select for update returns artistid = 1");
> +
> +        my $artist_from_schema2;
> +        my $error_ok = 0;
> +        eval {
> +            my $h = set_sig_handler( 'ALRM', sub { die "DBICTestTimeout" } );
> +            alarm(2);
> +            $artist_from_schema2 = $schema2->resultset('Artist')->find(1);
> +            $artist_from_schema2->name('fooey');
> +            $artist_from_schema2->update;
> +            alarm(0);
> +        };
> +        if (my $e = $@) {
> +            $error_ok = $e =~ /DBICTestTimeout/;
> +        }
> +
> +        # Make sure that an error was NOT raised, and that the update succeeded
> +        ok(! $error_ok, "update from second schema DOES NOT timeout");
> +        ok(! $artist_from_schema2->is_column_changed('name'), "'name' column is NOT dirty from second schema");
> +    });
> +}
> +
>  END {
>      if($dbh) {
>          $dbh->do("DROP TABLE testschema.artist;");
> Index: lib/DBIx/Class/Storage/DBI.pm
> ===================================================================
> --- lib/DBIx/Class/Storage/DBI.pm	(revision 3567)
> +++ lib/DBIx/Class/Storage/DBI.pm	(working copy)
> @@ -17,6 +17,9 @@
>         transaction_depth unsafe/
>  );
>  
> +__PACKAGE__->mk_group_accessors('inherited' => qw/sql_maker_class/);
> +__PACKAGE__->sql_maker_class('DBIC::SQL::Abstract');
> +
>  BEGIN {
>  
>  package DBIC::SQL::Abstract; # Would merge upstream, but nate doesn't reply :(
> @@ -81,6 +84,15 @@
>    my ($sql, @ret) = $self->SUPER::select(
>      $table, $self->_recurse_fields($fields), $where, $order, @rest
>    );
> +  $sql .= 
> +    $self->{for} ?
> +    (
> +      $self->{for} eq 'update' ? ' FOR UPDATE' :
> +      $self->{for} eq 'shared' ? ' FOR SHARE'  :
> +      ''
> +    ) :
> +    ''
> +  ;
>    return wantarray ? ($sql, @ret, @{$self->{having_bind}}) : $sql;
>  }
>  
> @@ -711,7 +723,8 @@
>  sub sql_maker {
>    my ($self) = @_;
>    unless ($self->_sql_maker) {
> -    $self->_sql_maker(new DBIC::SQL::Abstract( $self->_sql_maker_args ));
> +    my $sql_maker_class = $self->sql_maker_class;
> +    $self->_sql_maker($sql_maker_class->new( $self->_sql_maker_args ));
>    }
>    return $self->_sql_maker;
>  }
> @@ -1003,9 +1016,15 @@
>  sub _select {
>    my ($self, $ident, $select, $condition, $attrs) = @_;
>    my $order = $attrs->{order_by};
> +
>    if (ref $condition eq 'SCALAR') {
>      $order = $1 if $$condition =~ s/ORDER BY (.*)$//i;
>    }
> +
> +  my $for = delete $attrs->{for};
> +  my $sql_maker = $self->sql_maker;
> +  local $sql_maker->{for} = $for;
> +
>    if (exists $attrs->{group_by} || $attrs->{having}) {
>      $order = {
>        group_by => $attrs->{group_by},
> @@ -1023,6 +1042,7 @@
>        if (defined($attrs->{rows}) && !($attrs->{rows} > 0));
>      push @args, $attrs->{rows}, $attrs->{offset};
>    }
> +
>    return $self->_execute(@args);
>  }
>  
> Index: lib/DBIx/Class/Storage/DBI/Oracle/WhereJoins.pm
> ===================================================================
> --- lib/DBIx/Class/Storage/DBI/Oracle/WhereJoins.pm	(revision 3567)
> +++ lib/DBIx/Class/Storage/DBI/Oracle/WhereJoins.pm	(working copy)
> @@ -5,6 +5,8 @@
>  use strict;
>  use warnings;
>  
> +__PACKAGE__->sql_maker_class('DBIC::SQL::Abstract::Oracle');
> +
>  BEGIN {
>    package DBIC::SQL::Abstract::Oracle;
>  
> @@ -91,18 +93,6 @@
>    }
>  }
>  
> -sub sql_maker {
> -  my ($self) = @_;
> -
> -  unless ($self->_sql_maker) {
> -    $self->_sql_maker(
> -      new DBIC::SQL::Abstract::Oracle( $self->_sql_maker_args )
> -    );
> -  }
> -
> -  return $self->_sql_maker;
> -}
> -
>  1;
>  
>  __END__
> _______________________________________________
> List: http://lists.rawmode.org/cgi-bin/mailman/listinfo/dbix-class
> IRC: irc.perl.org#dbix-class
> SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
> Searchable Archive: http://www.grokbase.com/group/dbix-class@lists.rawmode.org

-- 
      Matt S Trout       Need help with your Catalyst or DBIx::Class project?
   Technical Director                    http://www.shadowcat.co.uk/catalyst/
 Shadowcat Systems Ltd.  Want a managed development or deployment platform?
http://chainsawblues.vox.com/            http://www.shadowcat.co.uk/servers/



More information about the DBIx-Class mailing list