# # this file implements index functions using DBI # package index_DBI; use strict qw(vars); use vars qw($Count); use HTML::Entities; use DBI; my %Table; # index tables which where visited in this run my %sth_cache; # cache prepared statements sub new { my $class = shift; my $self = {}; bless($self, $class); my $dbd = shift || die "need dbi_dbd= in [global] section of configuration file"; my $dsn = shift || die "need dbi_dsn= in [global] section of configuration file"; 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(); $Count++; return $self; } sub delete_and_create { my $self = shift; my $field = shift; #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), count int, ord int, primary key (item,ident) )"; $self->{dbh}->begin_work; $sth = $self->{dbh}->do($sql); # || warn "SQL: $sql ".$self->{dbh}->errstr(); $self->{dbh}->commit; $self->{dbh}->begin_work; } sub insert { my $self = shift; my $field = shift; my $index_data = shift || print STDERR "\$index->insert($field,NULL,...)"; my $ident = shift || ''; # e.g. library id 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(); if (! $sth_cache{$field."select"}->fetchrow_hashref) { $index_data = substr($index_data,0,255); $sth_cache{$field."insert"}->execute($index_data,$ident,1) || die "cache: $field insert; ".$self->{dbh}->errstr(); #print stderr "in index: $index_data\n"; } else { $sth_cache{$field."update"}->execute($index_data,$ident) || die "cache: $field update; ".$self->{dbh}->errstr(); } } sub check { my $self = shift; my $field = shift; my $sql = "select count(*) from $field"; my $sth = $self->{dbh}->prepare($sql) || die $self->{dbh}->errstr(); $sth->execute() || die "sql: $sql; ".$self->{dbh}->errstr(); my ($total) = $sth->fetchrow_array(); return $total; } sub fetch { my $self = shift; my $field = shift; my $what = shift || 'item'; # 'item,ident' my $where = shift; my $from_ord = shift || 0; my $rows = shift || 10; my @sql_args; my $sql = "select $what,ord from $field"; if ($where) { my $sql2 = " select ord from $field where upper($what) 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; } } $sql .= " order by ord limit $rows offset $from_ord"; my $sth = $self->{dbh}->prepare($sql) || die "prepare: $sql; ".$self->{dbh}->errstr(); $sth->execute() || die "execute: $sql; ".$self->{dbh}->errstr(); my @arr; while (my $row = $sth->fetchrow_hashref) { $row->{item} = HTML::Entities::encode($row->{item},'<>&"'); push @arr,$row; } return @arr; } sub close { my $self = shift; # re-create ord column (sorted order) in table sub create_ord { my $table = shift; $self->{dbh}->begin_work || die $self->{dbh}->errstr(); my $sql = "select oid from $table order by upper(item)"; 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}); } $self->{dbh}->commit || die $self->{dbh}->errstr(); } #--- end of sub if ($self->{dbh}) { # commit $self->{dbh}->commit || die $self->{dbh}->errstr(); foreach my $table (keys %Table) { # FIX 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"}; } $self->{dbh}->disconnect; undef $self->{dbh}; } } END { $Count--; print STDERR "index_DBI fatal error: \$index->close() not called... $Count references left!\n" if ($Count > 0); # FIX: debug output # print STDERR "usage\ttable\n"; # foreach (keys %Table) { # print STDERR $Table{$_},"\t$_\n"; # } } 1;