Mark Clements wrote:
> Oobi Van Doobi wrote:
>> Hi,
>> have some issues regarding tying of db records.
>> I have the past few days done a class/package that tie's a database
>> record to a hash. I am very happy with this solution, as I can just take
>> the CGI params and put them into the hash, and voila they are in the
>> database.
>>
>> But:What about speed? Could some kind soul please advice a little if this
>> (tie'ing records like this) is a good thing to do, or if I should take
>> another route.
>>
>> Background to the project:
>> 1)web application
>> 2)mod_perl to some extent
>> 3)number of users only about 5-10
>> 4)using MySQL
>>
>> Many thank's and have a good day
>
> Run some benchmarks (eg Benchmark::Timer) and establish where your code
> is spending most of its time. Decide whether your application is already
> fast enough. You can waste an awful lot of time trying to get minor
> speed-ups, time that could be spent on more productive tasks.
>
> If your existing codebase is composed of clear, maintainable code then
> you are already ahead of your game. Performance, especially in a small
Hmm, all is made as modules/packages. I have made even a Column in a table
as a package, that I tie to, also a record is a tied hash. The great thing
with tie'ing is flexibility. The same code applies naturally to all tables.
The hash package that I tie to a record checks for column types and column
names and use them as parameters with CGI. Then I can use the column
information as input types ( textarea, input, checkboxes and such) in the
gui part.
Here is the tied table record hash package:
<code>
package TransPool::Row;
use TransPool::Column;
use TransPool::ColumnTypes;
use DBI;
use TransPool:

ebug;
use strict;
my $DEBUG = TransPool:

ebug->new()->{DEBUG};
sub TIEHASH
{
#DB HANDLE, TABLE NAME
my $self = shift;
my $dbh = shift;
my $tname = shift;
my $idcol = shift;
my $cond = shift;
my $table =
{
DBH=>$dbh,
TABLENAME=>$tname,
IDCOL=>$idcol,
CONDITION=>$cond,
COLUMNS=>{},
ROWS=>undef,
};
my $rh;
my $qcond = $dbh->quote($cond);
my $sql_on_id_col = "SELECT $idcol FROM $tname WHERE $idcol = $qcond";
my $sth = $dbh->prepare($sql_on_id_col);
if ( !$sth->execute() )
{
print "error:$sql_on_id_col:$DBI::errstr";
return bless $table, $self;
}
if ( $sth->rows == 0 )
{
my $sql_insert = "INSERT INTO $tname ($idcol) VALUES($qcond)";
my $sth_insert = $dbh->prepare($sql_insert);
$sth_insert->execute() or print "insert failed:$sql_insert:$DBI::errstr";
return bless $table, $self;
}
return bless $table, $self;
}
sub FETCH
{
my $self = shift;
my $key = shift;
#( $dbh, $table, $column, $idcol, $id ) = @_;
tie
$self->{COLUMNS}{$key},
"Column",
$self->{DBH},
$self->{TABLENAME},
$key,
$self->{IDCOL},
$self->{CONDITION}
;
return $self->{COLUMNS}{$key};
}
sub STORE
{
my $self = shift;
my $key = shift;
my $value = shift;
tie
$self->{COLUMNS}{$key},
"Column",
$self->{DBH},
$self->{TABLENAME},
$key,
$self->{IDCOL},
$self->{CONDITION}
;
$self->{COLUMNS}{$key} = $value;
}
sub DELETE
{
my $self = shift;
return undef;
}
sub CLEAR
{
#deletes a record as identified by the condition
my $self = shift;
my $qval = $self->{DBH}->quote($self->{CONDITION});
my $sql = "DELETE FROM $self->{TABLENAME} WHERE $self->{IDCOL}=$qval";
my $sth = $self->{DBH}->prepare($sql);
if ( !$sth->execute() )
{
print "failed to delete record(s):$sql:$DBI::errstr\n";
}
}
sub EXISTS
{
my $self = shift;
my $key = shift;
return exists $self->{COLUMNS}{$key};
}
sub FIRSTKEY
{
my $self = shift;
return scalar each %{$self->{COLUMNS}{Field}};
}
sub NEXTKEY
{
my $self = shift;
return scalar each %{$self->{COLUMNS}{Field}};
}
sub DESTROY
{
my $self = shift;
return;
}
1;
</code>
For example, this is what I do:
here is a sample parameter value pair list from CGI:
<cgi>
TransporterUniqueId=1
TransporterName=Oola Bandoola
TransporterAddress=Adr1
TransporterAddress2=Adr2
TransporterTel=1234
TransporterFax=2345
TransporterEmail=
TransporterSite=www.ownsite.obi
TransporterCountry=1
</cgi>
so, when those parameters arrive on the server I can just do:
my %row;
tie %row, "TransPool::Row", ...parameters here....set unique id;
and then after getting the cgi object from mod_perl I can loop on cgi params
( to update only those present in the cgi object):
foreach my $p($cgi->param)
{
$row{p} = $cgi->param($p);
}
or to get only the specified set of params
my @ary;
foreach my $p($cgi->param)
{
push @ary, $row{p};
}
return @ary;
> application, is one of the last things you should worry about.
Yes, I guess you are right there, I'll go for maintainability and
flexibility and drop speed issues for now.
>
> Note: somebody else will be able to give your more details about the
> efficiency of tie. I never use it in my own code, and must admit have
> not even read the documentation for it in some time.
>
> Mark
General comments, or in particular, on this approach are very much welcome,
Thank's
Thank's for your input, Mark.
Greger