--- trunk/index_DBI_cache.pm 2003/07/13 14:44:03 93 +++ trunk/index_DBI_cache.pm 2004/01/31 20:57:48 206 @@ -2,11 +2,16 @@ # this file implements index functions using DBI # and huge amounts of memory for cache speedup # +# this version doesn't support ident (which sould be location in +# library). But, that functionality is not used anyway... +# package index_DBI; use strict qw(vars); use vars qw($Count); use HTML::Entities; +use URI::Escape; +use locale; use DBI; @@ -18,7 +23,16 @@ my $c_count; # bench time -my $t = time(); +my $bench_time = time(); + +sub bench { + my $self = shift; + my $msg = shift; + + print STDERR "last operation took ",time()-$bench_time," seconds...\n"; + $bench_time=time(); + print STDERR "$msg\n"; +} sub new { my $class = shift; @@ -30,12 +44,13 @@ my $user = shift || die "need dbi_user= in [global] section of configuration file"; my $passwd = shift || die "need dbi_passwd= in [global] section of configuration file"; - $self->{dbh} = DBI->connect("DBI:$dbd:$dsn",$user,$passwd) || die $DBI::errstr; - # begin transaction - $self->{dbh}->begin_work || die $self->{dbh}->errstr(); + $self->{dbd} = $dbd; + $self->{dbh} = DBI->connect("DBI:$dbd:$dsn",$user,$passwd) || die $DBI::errstr; $Count++; + $self->bench("connected to $dbd as $user"); + return $self; } @@ -46,30 +61,22 @@ #print "#### delete_and_create($field)\n"; - $self->{dbh}->commit; - my $sql = "select count(*) from $field"; my $sth = $self->{dbh}->prepare($sql) || die $self->{dbh}->errstr(); # FIX: this is not a good way to check if table exists! if ($sth->execute() && $sth->fetchrow_hashref) { my $sql = "drop table $field"; - $self->{dbh}->begin_work; my $sth = $self->{dbh}->do($sql) || die "SQL: $sql ".$self->{dbh}->errstr(); - $self->{dbh}->commit; } $sql = "create table $field ( item varchar(255), - ident varchar(255), + display text, count int, ord int, - primary key (item,ident) + primary key (item) )"; - $self->{dbh}->begin_work; - $sth = $self->{dbh}->do($sql); # || warn "SQL: $sql ".$self->{dbh}->errstr(); - $self->{dbh}->commit; - - $self->{dbh}->begin_work; + $sth = $self->{dbh}->do($sql) || warn "SQL: $sql ".$self->{dbh}->errstr(); } sub insert { @@ -77,25 +84,13 @@ my $field = shift; my $index_data = shift || print STDERR "\$index->insert($field,NULL,...)"; - my $ident = shift || ''; # e.g. library id + my $display = shift || $index_data; if (! $index_data) { print STDERR "\$index->insert() -- no value to insert\n"; return; } - if (! $Table{$field}) { - $self->delete_and_create($field); - - my $sql = "select item from $field where upper(item)=upper(?)"; - $sth_cache{$field."select"} = $self->{dbh}->prepare($sql) || die $self->{dbh}->errstr(); - - $sql = "insert into $field (item,ident,count) values (?,?,?)"; - $sth_cache{$field."insert"} = $self->{dbh}->prepare($sql) || die $self->{dbh}->errstr(); - - $sql = "update $field set count = count + 1 where item = ? and ident = ?"; - $sth_cache{$field."update"} = $self->{dbh}->prepare($sql) || die $self->{dbh}->errstr(); - } $Table{$field}++; #$sth_cache{$field."select"}->execute($index_data) || die "cache: $field select; ".$self->{dbh}->errstr(); @@ -108,29 +103,40 @@ $index_data = substr($index_data,0,255); my $uc = uc($index_data); - if (! $c_table->{$field}->{$ident}->{$uc}) { - $sth_cache{$field."insert"}->execute($index_data,$ident,0) || warn "cache: $field insert ($index_data,$ident); ".$self->{dbh}->errstr(); + if (! $c_table->{$field}->{$uc}) { #print stderr "in index: $index_data\n"; - $c_table->{$field}->{$ident}->{$uc} = $index_data; - $c_count->{$field}->{$ident}->{$uc} = 1; + $c_table->{$field}->{$uc} = $index_data; + $c_table->{$field}->{$uc}->{display} = $display; + $c_count->{$field}->{$uc} = 1; } else { - $c_count->{$field}->{$ident}->{$uc}++; + $c_count->{$field}->{$uc}++; } } -sub check { +sub count { my $self = shift; my $field = shift; + my $where = shift; - my $sql = "select count(*) from $field"; + my $sql = "select count(*) from $field where upper(item) like upper(?)||'%'"; my $sth = $self->{dbh}->prepare($sql) || die $self->{dbh}->errstr(); - $sth->execute() || die "sql: $sql; ".$self->{dbh}->errstr(); + $sth->execute($where) || die "sql: $sql; ".$self->{dbh}->errstr(); my ($total) = $sth->fetchrow_array(); - return $total; + # no results, count all + if (! $total) { + my $sql = "select count(*) from $field"; + + my $sth = $self->{dbh}->prepare($sql) || die $self->{dbh}->errstr(); + $sth->execute() || die "sql: $sql; ".$self->{dbh}->errstr(); + $total = $sth->fetchrow_array(); + + } + + return $total || 1; } @@ -138,7 +144,6 @@ my $self = shift; my $field = shift; - my $what = shift || 'item'; # 'item,ident' my $where = shift; my $from_ord = shift || 0; @@ -146,15 +151,24 @@ my @sql_args; - my $sql = "select $what,ord from $field"; + my $sql = "select item,display,ord from $field"; if ($where) { - my $sql2 = " select ord from $field where upper($what) like upper(?)||'%'"; + my $sql2 = "select ord from $field where upper(item) like upper(?)||'%'"; my $sth = $self->{dbh}->prepare($sql2) || die "sql2: $sql2; ".$self->{dbh}->errstr(); $sth->execute($where) || die "sql2: $sql2; ".$self->{dbh}->errstr(); if (my $row = $sth->fetchrow_hashref) { $from_ord += $row->{ord} - 1; + } else { + # if no match is found when searching from beginning + # of word in index, try substring match anywhere + $sql2 = "select ord from $field where upper(item) like '% '||upper(?)||'%'"; + $sth = $self->{dbh}->prepare($sql2) || die "sql2: $sql2; ".$self->{dbh}->errstr(); + $sth->execute($where) || die "sql2: $sql2; ".$self->{dbh}->errstr(); + if (my $row = $sth->fetchrow_hashref) { + $from_ord += $row->{ord} - 1; + } } } $sql .= " order by ord limit $rows offset $from_ord"; @@ -163,7 +177,8 @@ $sth->execute() || die "execute: $sql; ".$self->{dbh}->errstr(); my @arr; while (my $row = $sth->fetchrow_hashref) { - $row->{item} = HTML::Entities::encode($row->{item},'<>&"'); + $row->{item} = HTML::Entities::encode($row->{item},' <>&"'); + $row->{display} = HTML::Entities::encode($row->{display},'<>&"'); push @arr,$row; } return @arr; @@ -172,49 +187,41 @@ sub close { my $self = shift; + return if (! $self->{dbh}); - # re-create ord column (sorted order) in table - sub create_ord { - - my $table = shift; + foreach my $table (keys %Table) { + $self->bench("Crating table $table"); + $self->delete_and_create($table); $self->{dbh}->begin_work || die $self->{dbh}->errstr(); - my $sql = "select oid from $table order by upper(item)"; + $self->bench("Sorting ".$Table{$table}." items in $table"); + my @keys = sort keys %{$c_table->{$table}}; + + $self->bench("Dumping data into $table"); + my $sql = "insert into $table (ord,item,display,count) values (?,?,?,?)"; my $sth = $self->{dbh}->prepare($sql) || die "sql: $sql; ".$self->{dbh}->errstr(); - $sql = "update $table set ord=? where oid=?"; - my $sth_update = $self->{dbh}->prepare($sql) || die "sql: $sql; ".$self->{dbh}->errstr(); - $sth->execute() || die "sql: $sql; ".$self->{dbh}->errstr(); - my $ord = 1; - while (my $row = $sth->fetchrow_hashref) { - $sth_update->execute($ord++,$row->{oid}); + + my $ord = 0; + foreach my $key (@keys) { + $sth->execute(++$ord, + $c_table->{$table}->{$key}, + $c_table->{$table}->{$key}->{display}, + $c_count->{$table}->{$key} + ); } $self->{dbh}->commit || die $self->{dbh}->errstr(); } - #--- end of sub - if ($self->{dbh}) { - - # commit - $self->{dbh}->commit || die $self->{dbh}->errstr(); + if ($self->{dbd} =~ m/(Pg|SQLite)/) { + $self->{dbh}->do(qq{vacuum}) || warn "vacumming failed. It shouldn't if you are using PostgreSQL or SQLite: ".$self->{dbh}->errstr(); + } - foreach my $table (keys %Table) { -# FIX -print STDERR "last operation took ",time()-$t," seconds...\n"; -$t=time(); -print STDERR "creating ord for $table...\n"; - create_ord($table); - undef $sth_cache{$table."select"}; - undef $sth_cache{$table."insert"}; - undef $sth_cache{$table."update"}; -# XXX -# $sth_cache{$field."update"}->execute($index_data,$ident) || die "cache: $field update; ".$self->{dbh}->errstr(); - } + $self->bench("disconnecting from database"); - $self->{dbh}->disconnect; - undef $self->{dbh}; - } + $self->{dbh}->disconnect; + undef $self->{dbh}; } END {