[Catalyst] Downloading BLOBs
Toby Corkindale
toby at ymogen.net
Tue May 9 15:16:14 CEST 2006
(This is related to my discussion of BLOBs via DBIx::Class on their list)
Given a $c->stash->{content_oid} that contains a PostgreSQL OID for a
large object, this should cause Catalyst::Engine to send it to the
client without slurping the entire contents into ram:
sub finalize_body {
my $c = shift;
if (defined $c->stash->{'content_oid'}) {
$c->log->debug("In custom finalize_body() routine..");
# This handle should be a Postgres large object ID
my $oid = $c->stash->{'content_oid'};
my $dbh = $c->model('DB')->schema->storage->dbh;
$c->model('DB')->schema->txn_begin;
my $io = IO::BLOB::Pg->new($dbh, $oid);
die("Failed to create IO::BLOB::Pg") unless defined $io;
$c->response->body($io);
$c->NEXT::finalize_body;
$c->model('DB')->schema->txn_commit;
}
else {
$c->NEXT::finalize_body;
}
return $c;
}
It's rather hacky, but I thought I'd submit it for your comments.
I'll try and create a DBIx::Class::..::BLOB interface at some point, and
if I do, I'll definately arrange it so it hopefully doesn't require the
hacky transaction-surrounding bits.
Also, I have a bad feeling about doing the transaction with
begin/commit, rather than the txn_do( sub {} ) method.. However, that's
not available, due to NEXT not functioning within an anonymous sub (of
course).
An alternative is to just call $c->engine->finalize_body( $c, @_ );
inside the txn_do() sub, instead of NEXTing onto it. I think I prefer
that method, since it allows us to end the transaction in case of
death.. but it breaks any other plugins.
$c->model('DB')->schema->txn_do( sub {
my $io = IO::BLOB::Pg->new($dbh, $oid);
die("Failed to create IO::BLOB::Pg") unless defined $io;
$c->response->body($io);
$c->engine->finalize_body( $c, @_ );
});
Any suggestions?
(It seems like "write the D::C plugin already" is the neat solution,
although I won't ahve time to do that immediately)
Cheers,
Toby
More information about the Catalyst
mailing list