188 lines
5.5 KiB
Perl
188 lines
5.5 KiB
Perl
# ==================================================================
|
|
# 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;
|