Class::DBI

Oh, OK then.

package ModelBase;
use base qw(Class::DBI);
use strict;
__PACKAGE__->set_db('Main', 'dbi:Pg:dbname=hr', '', '');
__PACKAGE__->sequence('id_seq');
1;

package Product;
## uses CGI::Untaint to validate columns 
use Class::DBI::FromCGI;
use base qw(ModelBase);
use strict;

__PACKAGE__->table('product');
__PACKAGE__->columns('Primary' => qw!id!);
__PACKAGE__->columns(
  'Essential' => qw!name range type code price img_path!
);
__PACKAGE__->columns('Other' => qw!wholesale_price stock_quantity!);
__PACKAGE__->has_a('type' => 'Product::Type');
__PACKAGE__->has_a('range' =>'Product::Range'); 
__PACKAGE__->untaint_columns(
  'printable' => [qw!name code price wholesale_price 
                     stock_quantity img_path!]
,
  'integer'   => [qw!range type!],
);
1;

## elsewhere
$args{product} = Product->create_from_cgi($h);
$args{errors} = $args{product}->cgi_update_errors();
unless ($args{errors}) { 
  $args{product}->update(); 
  $args{product}->dbi_commit();
}

$args{product} = Product->retrieve($1);
print $args{product}->name;