[Catalyst] Adding Functionality to Class::DBI::Sweet for Oracle
Anthony Lee
anthony.lee at uk.tiscali.com
Mon Jun 6 17:18:31 CEST 2005
Appologies if this is going to the wrong mailing list,
I've subclassed Catalyst::Model::CDBI::Sweet to support Oracle paging. I am
not entirely sure this works, but wondered how I can get this into the main
distribution if it does work. I've tried to make paging work in Oracle via a
subselect like (see code below):-
select __ESSENTIAL__ FROM
( SELECT ROWNUM N, C.* FROM __TABLE__ C WHERE ROWNUM <= ($rownum+$offset)
AND $sql )
WHERE N > $offset
Does this make sense ??
Secondly, can somebody tell me if the caching in CDBI::Sweet, works with
HAS_A relationships. I presume the Cache::FastMmap only stores the
individual deflated object, and when I call the relationship method the
foreign object is inflated via a cache ( and everything just works ??)
e.g
package MyApp::COMP;
use base qw[Class::DBI::Sweet];
__PACKAGE__->table('component');
__PACKAGE__->columns(Essential=>qw/componentid componentname parentid/);
__PACKAGE__->cache(Cache::FastMmap->new());
__PACKAGE__->has_a(parent=>'MyApp::COMP');
=====================
use MyApp::COMP;
$obj=MyApp::COMP->retrieve($id);
while ($obj && $obj->parentid->id != 0) {
print $obj->componentname;
$obj=$obj->parentid;
}
I have something very similar above, except $obj->parentid doesn't always
seem to return a blessed object. However when I remove the
__PACKAGE__->cache statement my app code always seems to work.
Any comments much appreciated.
Anthony
<<CODE FOR SUPPORTING ORACLE within CDBI::Sweet>>
package <PACKAGE>::SweetOracle;
use strict;
use base qw[Class::DBI::Sweet Catalyst::Base];
our $VERSION = '0.01';
*new = \&Catalyst::Base::new;
__PACKAGE__->set_sql( SweetOracleRetrieve => <<'SQL' );
SELECT __ESSENTIAL__
FROM %s
WHERE %s
SQL
sub search {
my $proto = shift;
my $class = ref($proto) || $proto;
my ( $criteria, $attributes ) = $class->_search_args(@_);
my ( $sql, $columns, $values, $table ) = $proto->_search( $criteria,
$attributes );
my $sth = $class->sql_SweetOracleRetrieve($table,$sql);
$class->_bind_param( $sth, $columns );
my $iterator = $class->sth_to_objects( $sth, $values );
# If RDBM is not ROWS/OFFSET supported, slice iterator
if ( $attributes->{rows} && $iterator->count > $attributes->{rows} ) {
my $rows = $attributes->{rows};
my $offset = $attributes->{offset} || 0;
$iterator = $iterator->slice( $offset, $offset + $rows - 1 );
}
return map $class->construct($_), $iterator->data if wantarray;
return $iterator;
}
sub _search {
my $proto = shift;
my $criteria = shift;
my $attributes = shift;
my $class = ref($proto) || $proto;
# Valid SQL::Abstract params
my %params = map { $_ => $attributes->{$_} } qw(case cmp convert logic);
my $table=$class->table;
# Overide bindtype, we need all columns and values for deflating
my $abstract = SQL::Abstract->new( %params, bindtype => 'columns' );
my ( $sql, @bind ) = $abstract->where( $criteria,
$attributes->{order_by} );
my ( @columns, @values, %cache );
while ( my $bind = shift(@bind) ) {
my $col = shift(@$bind);
my $column = $cache{$col};
unless ($column) {
$column = $class->find_column($col)
|| ( List::Util::first { $_->accessor eq $col }
$class->columns )
|| $class->_croak("$col is not a column of $class");
$cache{$col} = $column;
}
while ( my $value = shift(@$bind) ) {
push( @columns, $column );
push( @values, $class->_deflated_column( $column, $value ) );
}
}
unless ($attributes->{rows} ) {
# If paging is not required.
unless ( $sql =~ /^\s*WHERE/i ) {
$sql = "WHERE 1=1 $sql"
}
} else {
my $rows = $attributes->{rows};
my $offset = $attributes->{offset} || 0;
my $driver = $class->db_Main->{Driver}->{Name};
if ( $driver =~ /^Oracle$/ ) {
unless ( $sql =~ /^\s*WHERE/i ) {
$table = qq/( SELECT ROWNUM N, C.* FROM $table C WHERE
ROWNUM <= ? $sql )/;
push( @columns,'__ROWS');
push( @values, $offset + $rows);
} else {
$sql =~s|WHERE||;
$table = qq/( SELECT ROWNUM N, C.* FROM $table C WHERE
ROWNUM <= ? AND $sql )/;
unshift( @columns,'__ROWS');
unshift( @values, $offset + $rows);
}
$sql = "WHERE N > ?";
push (@columns,'__OFFSET');
push (@values,$offset);
} else {
# Original Logic to Add WHERE CONDITION
unless ( $sql =~ /^\s*WHERE/i ) {
$sql = "WHERE 1=1 $sql"
}
}
if ( $driver =~ /^(maxdb|mysql|mysqlpp)$/ ) {
$sql .= ' LIMIT ?, ?';
push( @columns, '__OFFSET', '__ROWS' );
push( @values, $offset, $rows );
}
if ( $driver =~ /^(pg|pgpp|sqlite|sqlite2)$/ ) {
$sql .= ' LIMIT ?, OFFSET ?';
push( @columns, '__ROWS', '__OFFSET' );
push( @values, $rows, $offset );
}
if ( $driver =~ /^(interbase)$/ ) {
$sql .= ' ROWS ? TO ?';
push( @columns, '__ROWS', '__OFFSET' );
push( @values, $rows, $offset + $rows );
}
}
$sql =~ s/^\s*(WHERE)\s*//i;
return ( $sql, \@columns, \@values ,$table);
}
1;
More information about the Catalyst
mailing list