Category Archives: Perl

Using DBIx::Class::Tree::NestedSet

I’ve been struggling to get DBIx::Class::Tree::NestedSet working today because I found the documentation a bit sparse.

The problem is basically that the instructions assume that I’m very familiar with DBIx::Class, and that therefore I don’t need much detail.

After much trial and error I got it to work.

So these notes are aimed at someone who has got the basics of DBIx::Class running, with all the clever schema classes created (either manually or via something like dbicdump).

For this example, the tree is in a table called ‘treetable’, whose schema is defined in App::DB::Schema.  The table needs to have the following columns, in addition to the ones that you need for your application:


  id       INTEGER PRIMARY KEY AUTOINCREMENT,
  root_id  integer,
  lft      integer NOT NULL,
  rgt      integer NOT NULL,
  level    integer NOT NULL,

This line:

__PACKAGE__->load_components(qw( Tree::NestedSet ... ));

needs to go near the bottom of App::DB::Schema.pm, after the ‘DO NOT MODIFY THIS OR ANYTHING ABOVE!‘ line.  Note that the ellipsis (...) needs to be either deleted or replaced with any components that you’re already using.

These lines:

__PACKAGE__->tree_columns({
    root_column  => 'root_id',
    left_column  => 'lft',
    right_column => 'rgt',
    level_column => 'level',
});

go in App::DB::Schema::Result::Treetable.pm, after the ‘DO NOT MODIFY THIS OR ANYTHING ABOVE!‘ line, and with the column names set to match the ones in your table.

That same file, App::DB::Schema::Result::Treetable.pm, is the one that needs

use parent DBIx::Class::Tree::NestedSet;

near the top.

Once that all compiles cleanly, you can start accessing the tree table.

Start by creating the result set in the usual DBIC way:

my $rs = $schema->resultset('Treetable');

where $schema is your database handle.

Then you can start using the tree relationships and methods however you like.  Note that the documentation uses $node to refer to each node in the tree: each such $node is a DBIC object that can be used to access the fields from the corresponding database row, navigate to other nodes (children, siblings, etc.), or create new children or siblings.

For example,

my $first = $rs->first;  # get the first (or only) root node
my $desc_rs = $first->descendants;
while (my $desc = $desc_rs->next) { 
    print '**'x$desc->level, " id=", $desc->id, 
        ", field1=", $desc->name, "\n";
}

I hope that makes sense.

Arch Linux — updating Perl from 5.14 to 5.16

Recent updates (in June 2012) to Arch Linux replaced Perl 5.14 with 5.16.

Imagine my surprise when Perl scripts (including cpanp) suddenly stopped working.

I asked about the problem on PerlMongers and the Arch Linux forum, and did the following to solve it:

  • Delete all files under /usr/bin/site_perl, /usr/lib/perl5/site_perl and /usr/share/perl5/site_perl to remove the duplicates installed by the cpan shell.
  • Rebuild all AUR packages that contain perl XS modules. This will print them out:
    sudo pacman -Qml | awk '/_perl/auto/.+.so$/ { print $1 }' | uniq

    (There weren't any on my system.)

  • Reinstall perl-cpanplus-dist-arch
  • Run cpanp to install the Perl modules that aren't available on Arch or AUR, for example:
    sudo cpanp -i Math::Combinatorics

Which seems to have done the job.

Signals in Perl, 5.10.1 vs 5.14.2

A Perl script that I've been working on wasn't working properly with Perl 5.14.2.

It turned out that the problem was really with my use of local signal handlers.

The following code works with 5.10.1 but not with 5.14.2:

#!/usr/bin/perl
use strict;
use warnings;
print "starting pid=$$n";
my $I = 0;
{
  my $pid = 0;
  sub handler {
    my $sig = shift;
    $I += 1;
    print "caught $sign";
    local $SIG{$sig} = 'IGNORE'; # doesn't work with local!!
    kill($sig, -$$);
    print "end of handlern";
  }
  local $SIG{INT} = &handler;
  kill('INT', $$);
}
print "ending I=$In";

With 5.10.1, it calls handler() twice and then exits with I=2; with 5.14.2 it calls the handler many times before crashing with a segfault.

Removing the local from the inner $SIG{$sig} allows it to work with 5.14.2, which makes sense if I'm right in thinking that that command changes the immediately-containing signal handler, and not the global one.

I found the Perl documentation a bit vague on this topic, so this is here in case it's useful to someone else.