# ================================================================== # Gossamer Threads Module Library - http://gossamer-threads.com/ # # GT::Search::MYSQL::Indexer # Author : Aki Mimoto # CVS Info : 087,071,086,086,085 # $Id: Indexer.pm,v 1.17 2004/08/28 03:53:49 jagerman Exp $ # # Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved. # ================================================================== # # Description: # Class used to search indexed tables. # package GT::SQL::Search::MYSQL::Indexer; # ------------------------------------------------------------------------------ use strict; use vars qw/@ISA $VERSION $DEBUG $ERRORS $ERROR_MESSAGE/; use GT::SQL::Search::Base::Indexer; @ISA = qw/GT::SQL::Search::Base::Indexer/; $DEBUG = 0; $VERSION = sprintf "%d.%03d", q$Revision: 1.17 $ =~ /(\d+)\.(\d+)/; $ERRORS = { NOTFROMWEB => 'There are far too many records in table %s for create/destroy of this indexing scheme from the web. Please use alternative method.', MYSQLNONSUPPORT => 'Driver MYSQL requires MySQL version 3.23.23 or greater. Currently MySQL version: %s' }; @$GT::SQL::ERRORS{ keys %$ERRORS } = values %$ERRORS; $ERROR_MESSAGE = 'GT::SQL'; sub load { my $class = shift; return $class->new(@_); } sub ok { # ------------------------------------------------------------------------------ my ($class, $tbl) = @_; unless (uc $tbl->{connect}->{driver} eq 'MYSQL') { return $class->error ('MYSQLNONSUPPORT', 'WARN', $tbl->{connect}->{driver}); } my $sth = $tbl->do_query(qq!SELECT VERSION()!); my $version = $sth->fetchrow; my ($maj, $min) = split (/\./, $version); unless ($maj > 3 or ($maj == 3 and $min >= 23)) { return $class->error(MYSQLNONSUPPORT => WARN => $version); } return 1; } sub drop_search_driver { # ------------------------------------------------------------------------------ my $self = shift; $self->too_much() and return; my $tbl = $self->{table} or return; $tbl->connect(); my %weights = $tbl->weight() or return; my $tblname = $tbl->name(); # Group the fulltext columns by value of the weight my %cols_grouped; foreach ( keys %weights ) { my $val = $weights{$_} or next; push @{$cols_grouped{$val}}, $_; } # Drop unified fulltext columns if required if ( keys %cols_grouped > 1 ) { $cols_grouped{-1} = [ grep { $weights{$_} } keys %weights ]; } # For each value grouped column set create a full text # column foreach my $v ( keys %cols_grouped ) { my $ft_name = 'ft_'.join("_", sort @{$cols_grouped{$v}}); my $res = eval { $tbl->do_query(qq! ALTER TABLE $tblname DROP INDEX $ft_name !); }; # Break on errors that can't be handled if ( $@ ) { next if $@ !~ /exist/i; $self->warn( "$@" ); return; } } return 1; } sub add_search_driver { # ------------------------------------------------------------------------------ my $self = shift; $self->too_much() and return; my $tbl = $self->{table} or return $self->error(BADARGS => FATAL => "table must be passed into add_search_driver."); my %weights = $tbl->weight() or return $self->error(NOWEIGHTS => 'WARN'); my $tblname = $tbl->name() or return $self->error(BADARGS => FATAL => "table does not have a name?"); # group the fulltext columns by value of the weight my %cols_grouped; foreach ( keys %weights ) { my $val = $weights{$_} or next; push @{$cols_grouped{$val}}, $_; } # Create unified fulltext columns if required if ( keys %cols_grouped > 1 ) { $cols_grouped{-1} = [ grep { $weights{$_} } keys %weights ]; } # for each value grouped column set create a full text # column foreach my $v ( keys %cols_grouped ) { my $cols = join(",", sort @{$cols_grouped{$v}}); my $ft_name = 'ft_'.join("_", sort @{$cols_grouped{$v}}); my $res = eval { $tbl->do_query(qq! ALTER TABLE $tblname ADD FULLTEXT $ft_name ( $cols ) !); }; # break on errors that can't be handled if ( $@ ) { next if $@ =~ /duplicate/i; $self->warn( "$@" ); return; } } return 1; } sub too_much { # ------------------------------------------------------------------------------ # returns true if there are too many records to be used on the Web # if ( $ENV{REQUEST_METHOD} ) { my $self = shift; my $tbl = $self->{table}; if ( $tbl->count() > 5000 ) { $self->error( 'NOTFROMWEB', 'WARN', $tbl->name() ); return 1 } } return; } sub post_create_table { # ------------------------------------------------------------------------------ shift->add_search_driver(@_); } sub reindex_all { # ------------------------------------------------------------------------------ # this will drop all the fulltext columns and reindex all of them. This should # not be required unless the user changes the weights on one of their columns. # Unfortunately, this method is not particularly smart and risks not dropping # certain index columns and reindexes even when it's not required. It must be # recoded at a future date, but as this action won't happen frequently and will # rarely affect the user, it is not a priority. # my $self = shift; $self->drop_search_driver; $self->add_search_driver; } 1;