From aa53ccbf4a47f6a12027a889d32dc05b2548f742 Mon Sep 17 00:00:00 2001 From: Jared Camins-Esakov Date: Tue, 11 Dec 2012 12:52:40 -0500 Subject: [PATCH] Bug 9239: Allow the use of QueryParser for all queries With the inclusion of this patch, all searches will (try) to use QueryParser for handling queries for both the bibliographic and authority databases if UseQueryParser is enabled. If QueryParser is unavailable, UseQueryParser is disabled, or the search uses CCL indexes, the old search code will be used. To test: 1) Apply patch. 2) Run the unit test with `prove t/QueryParser.t` 3) Enable the UseQueryParser syspref. 4) Try searches that should return results in the following places: * OPAC (simple search) * OPAC (advanced search) * OPAC (authorities) * Staff client (header search) * Staff client (advanced search) * Staff client (cataloging search) * Staff client (authorities) * Staff client (importing a batch using a match point) * Staff client (searching for an item for adding to a label) * Staff client (acquisitions) * Staff client (searching for a record to create a serial) * ANYWHERE ELSE I HAVE FORGOTTEN 5) Disable the UseQueryParser syspref. Repeat at least some of the searches you did above. 6) If all searches worked, sign off. Signed-off-by: Chris Cormack --- C4/AuthoritiesMarc.pm | 40 ++++++- C4/Matcher.pm | 55 +++++----- C4/Search.pm | 112 +++++++++++++------- Koha/SuggestionEngine/Plugin/AuthorityFile.pm | 2 +- cataloguing/addbooks.pl | 10 +- .../value_builder/marc21_linking_section.pl | 10 +- cataloguing/value_builder/unimarc_field_4XX.pl | 10 +- labels/label-item-search.pl | 25 +++-- misc/migration_tools/bulkmarcimport.pl | 22 +++- serials/subscription-bib-search.pl | 18 +++- 10 files changed, 219 insertions(+), 85 deletions(-) diff --git a/C4/AuthoritiesMarc.pm b/C4/AuthoritiesMarc.pm index 4a3392f..d68db86 100644 --- a/C4/AuthoritiesMarc.pm +++ b/C4/AuthoritiesMarc.pm @@ -201,6 +201,9 @@ sub SearchAuthorities { } } else { my $query; + my $qpquery = ''; + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); my $attr = ''; # the marclist may contain "mainentry". In this case, search the tag_to_report, that depends on # the authtypecode. Then, search on $a of this tag_to_report @@ -219,6 +222,9 @@ sub SearchAuthorities { if ($n>1){ while ($n>1){$query= "\@or ".$query;$n--;} } + if ($QParser) { + $qpquery .= '(authtype:' . join('|| authtype:', @auths) . ')'; + } } my $dosearch; @@ -276,6 +282,9 @@ sub SearchAuthorities { $q2 .=$attr; $dosearch=1; ++$attr_cnt; + if ($QParser) { + $qpquery .= " $tags->[$i]:$value->[$i]"; + } }#if value } ##Add how many queries generated @@ -296,8 +305,21 @@ sub SearchAuthorities { } elsif ($sortby eq 'AuthidDsc') { $orderstring = '@attr 7=2 @attr 4=109 @attr 1=Local-Number 0'; } - $query=($query?$query:"\@attr 1=_ALLRECORDS \@attr 2=103 ''"); - $query="\@or $orderstring $query" if $orderstring; + if ($QParser) { + $qpquery .= ' all:all' unless $value->[0]; + + if ( $value->[0] =~ m/^qp=(.*)$/ ) { + $qpquery = $1; + } + + $qpquery .= " #$sortby"; + + $QParser->parse( $qpquery ); + $query = $QParser->target_syntax('authorityserver'); + } else { + $query=($query?$query:"\@attr 1=_ALLRECORDS \@attr 2=103 ''"); + $query="\@or $orderstring $query" if $orderstring; + } $offset=0 unless $offset; my $counter = $offset; @@ -406,7 +428,7 @@ sub CountUsage { } else { ### ZOOM search here my $query; - $query= "an=".$authid; + $query= "an:".$authid; my ($err,$res,$result) = C4::Search::SimpleSearch($query,0,10); if ($err) { warn "Error: $err from search $query"; @@ -910,11 +932,19 @@ sub FindDuplicateAuthority { $sth->finish; # warn "record :".$record->as_formatted." auth_tag_to_report :$auth_tag_to_report"; # build a request for SearchAuthorities - my $query='at='.$authtypecode.' '; + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); + my $op; + if ($QParser) { + $op = '&&'; + } else { + $op = 'and'; + } + my $query='at:'.$authtypecode.' '; my $filtervalues=qr([\001-\040\!\'\"\`\#\$\%\&\*\+,\-\./:;<=>\?\@\(\)\{\[\]\}_\|\~]); if ($record->field($auth_tag_to_report)) { foreach ($record->field($auth_tag_to_report)->subfields()) { - $_->[1]=~s/$filtervalues/ /g; $query.= " and he,wrdl=\"".$_->[1]."\"" if ($_->[0]=~/[A-z]/); + $_->[1]=~s/$filtervalues/ /g; $query.= " $op he:\"".$_->[1]."\"" if ($_->[0]=~/[A-z]/); } } my ($error, $results, $total_hits) = C4::Search::SimpleSearch( $query, 0, 1, [ "authorityserver" ] ); diff --git a/C4/Matcher.pm b/C4/Matcher.pm index c0634ec..6a7c4f2 100644 --- a/C4/Matcher.pm +++ b/C4/Matcher.pm @@ -626,6 +626,8 @@ sub get_matches { my %matches = (); + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); foreach my $matchpoint (@{ $self->{'matchpoints'} }) { my @source_keys = _get_match_keys($source_record, $matchpoint); next if scalar(@source_keys) == 0; @@ -634,31 +636,36 @@ sub get_matches { my $error; my $searchresults; my $total_hits; - if ($self->{'record_type'} eq 'biblio') { - $query = join(" or ", map { "$matchpoint->{'index'}=$_" } @source_keys); -# FIXME only searching biblio index at the moment + if ($QParser) { + $query = join(" || ", map { "$matchpoint->{'index'}:$_" } @source_keys); require C4::Search; - ($error, $searchresults, $total_hits) = C4::Search::SimpleSearch($query, 0, $max_matches); - } elsif ($self->{'record_type'} eq 'authority') { - my $authresults; - my @marclist; - my @and_or; - my @excluding = []; - my @operator; - my @value; - foreach my $key (@source_keys) { - push @marclist, $matchpoint->{'index'}; - push @and_or, 'or'; - push @operator, 'exact'; - push @value, $key; - } - require C4::AuthoritiesMarc; - ($authresults, $total_hits) = C4::AuthoritiesMarc::SearchAuthorities( - \@marclist, \@and_or, \@excluding, \@operator, - \@value, 0, 20, undef, 'AuthidAsc', 1 - ); - foreach my $result (@$authresults) { - push @$searchresults, $result->{'authid'}; + ($error, $searchresults, $total_hits) = C4::Search::SimpleSearch($query, 0, $max_matches, [ $self->{'record_type'} . 'server' ] ); + } else { + if ($self->{'record_type'} eq 'biblio') { + $query = join(" or ", map { "$matchpoint->{'index'}=$_" } @source_keys); + require C4::Search; + ($error, $searchresults, $total_hits) = C4::Search::SimpleSearch($query, 0, $max_matches); + } elsif ($self->{'record_type'} eq 'authority') { + my $authresults; + my @marclist; + my @and_or; + my @excluding = []; + my @operator; + my @value; + foreach my $key (@source_keys) { + push @marclist, $matchpoint->{'index'}; + push @and_or, 'or'; + push @operator, 'exact'; + push @value, $key; + } + require C4::AuthoritiesMarc; + ($authresults, $total_hits) = C4::AuthoritiesMarc::SearchAuthorities( + \@marclist, \@and_or, \@excluding, \@operator, + \@value, 0, 20, undef, 'AuthidAsc', 1 + ); + foreach my $result (@$authresults) { + push @$searchresults, $result->{'authid'}; + } } } diff --git a/C4/Search.pm b/C4/Search.pm index 50f7d2b..cdddbaa 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -100,9 +100,22 @@ sub FindDuplicate { if ( $result->{isbn} ) { $result->{isbn} =~ s/\(.*$//; $result->{isbn} =~ s/\s+$//; - $query = "isbn=$result->{isbn}"; + $query = "isbn:$result->{isbn}"; } else { + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); + my $titleindex; + my $authorindex; + + if ($QParser) { + $titleindex = 'title|exact'; + $authorindex = 'author|exact'; + } else { + $titleindex = 'ti,ext'; + $authorindex = 'au,ext'; + } + $result->{title} =~ s /\\//g; $result->{title} =~ s /\"//g; $result->{title} =~ s /\(//g; @@ -111,8 +124,8 @@ sub FindDuplicate { # FIXME: instead of removing operators, could just do # quotes around the value $result->{title} =~ s/(and|or|not)//g; - $query = "ti,ext=$result->{title}"; - $query .= " and itemtype=$result->{itemtype}" + $query = "$titleindex:\"$result->{title}\""; + $query .= " && itemtype:$result->{itemtype}" if ( $result->{itemtype} ); if ( $result->{author} ) { $result->{author} =~ s /\\//g; @@ -122,7 +135,7 @@ sub FindDuplicate { # remove valid operators $result->{author} =~ s/(and|or|not)//g; - $query .= " and au,ext=$result->{author}"; + $query .= " && $authorindex:\"$result->{author}\""; } } @@ -226,11 +239,21 @@ sub SimpleSearch { my $results = []; my $total_hits = 0; + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser') && ! ($query =~ m/\w,\w|\w=\w/)); + # Initialize & Search Zebra for ( my $i = 0 ; $i < @servers ; $i++ ) { eval { $zconns[$i] = C4::Context->Zconn( $servers[$i], 1 ); - $zoom_queries[$i] = new ZOOM::Query::CCL2RPN( $query, $zconns[$i]); + if ($QParser) { + $query =~ s/=/:/g; + $QParser->parse( $query ); + $query = $QParser->target_syntax($servers[$i]); + $zoom_queries[$i] = new ZOOM::Query::PQF( $query, $zconns[$i]); + } else { + $zoom_queries[$i] = new ZOOM::Query::CCL2RPN( $query, $zconns[$i]); + } $tmpresults[$i] = $zconns[$i]->search( $zoom_queries[$i] ); # error handling @@ -1093,7 +1116,9 @@ on authority data). =cut sub _handle_exploding_index { - my ( $index, $term ) = @_; + my ($QParser, $struct, $filter, $params, $negate, $server) = @_; + my $index = $filter; + my $term = join(' ', @$params); return unless ($index =~ m/(su-br|su-na|su-rl)/ && $term); @@ -1101,8 +1126,8 @@ sub _handle_exploding_index { my $codesubfield = $marcflavour eq 'UNIMARC' ? '5' : 'w'; my $wantedcodes = ''; - my @subqueries = ( "(su=\"$term\")"); - my ($error, $results, $total_hits) = SimpleSearch( "Heading,wrdl=$term", undef, undef, [ "authorityserver" ] ); + my @subqueries = ( "su:\"$term\""); + my ($error, $results, $total_hits) = SimpleSearch( "he:$term", undef, undef, [ "authorityserver" ] ); foreach my $auth (@$results) { my $record = MARC::Record->new_from_usmarc($auth); my @references = $record->field('5..'); @@ -1116,11 +1141,13 @@ sub _handle_exploding_index { } foreach my $reference (@references) { my $codes = $reference->subfield($codesubfield); - push @subqueries, '(su="' . $reference->as_string('abcdefghijlmnopqrstuvxyz') . '")' if (($codes && $codes eq $wantedcodes) || !$wantedcodes); + push @subqueries, 'su:"' . $reference->as_string('abcdefghijlmnopqrstuvxyz') . '"' if (($codes && $codes eq $wantedcodes) || !$wantedcodes); } } } - return join(' or ', @subqueries); + my $query = '(' x scalar(@subqueries) . join(') || ', @subqueries) . ')'; + warn $query; + return $query; } =head2 parseQuery @@ -1147,37 +1174,42 @@ sub parseQuery { my $query = $operands[0]; my $index; my $term; + my $query_desc; -# TODO: once we are using QueryParser, all this special case code for -# exploded search indexes will be replaced by a callback to -# _handle_exploding_index - if ( $query =~ m/^(.*)\b(su-br|su-na|su-rl)[:=](\w.*)$/ ) { - $query = $1; - $index = $2; - $term = $3; - } else { + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser') || $query =~ s/^qp=//); + undef $QParser if ($query =~ m/^(ccl=|pqf=|cql=)/ || grep (/\w,\w|\w=\w/, @operands) ); + + if ($QParser) + { $query = ''; - for ( my $i = 0 ; $i <= @operands ; $i++ ) { - if ($operands[$i] && $indexes[$i] =~ m/(su-br|su-na|su-rl)/) { - $index = $indexes[$i]; - $term = $operands[$i]; - } elsif ($operands[$i]) { - $query .= $operators[$i] eq 'or' ? ' or ' : ' and ' if ($query); - $query .= "($indexes[$i]:$operands[$i])"; - } + for ( my $ii = 0 ; $ii <= @operands ; $ii++ ) { + next unless $operands[$ii]; + $query .= $operators[ $ii - 1 ] eq 'or' ? ' || ' : ' && ' + if ($query); + $query .= + ( $operators[$ii] ? "$operators[$ii]:" : '' ) . $operands[$ii]; + } + foreach my $limit (@limits) { + } + foreach my $modifier (@sort_by) { + $query .= " #$modifier"; } - } - if ($index) { - my $queryPart = _handle_exploding_index($index, $term); - if ($queryPart) { - $query .= "($queryPart)"; + $query_desc = $query; + if ( C4::Context->preference("QueryWeightFields") ) { } - $operators = (); - $operands[0] = "ccl=$query"; + $QParser->add_bib1_filter_map( 'biblioserver', 'su-br', { 'callback' => \&_handle_exploding_index }); + $QParser->add_bib1_filter_map( 'biblioserver', 'su-na', { 'callback' => \&_handle_exploding_index }); + $QParser->add_bib1_filter_map( 'biblioserver', 'su-rl', { 'callback' => \&_handle_exploding_index }); + $QParser->parse( $query ); + $operands[0] = "pqf=" . $QParser->target_syntax('biblioserver'); +# TODO: once we are using QueryParser, all this special case code for +# exploded search indexes will be replaced by a callback to +# _handle_exploding_index } - return ( $operators, \@operands, $indexes, $limits, $sort_by, $scan, $lang); + return ( $operators, \@operands, $indexes, $limits, $sort_by, $scan, $lang, $query_desc); } =head2 buildQuery @@ -1201,7 +1233,8 @@ sub buildQuery { warn "---------\nEnter buildQuery\n---------" if $DEBUG; - ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang) = parseQuery($operators, $operands, $indexes, $limits, $sort_by, $scan, $lang); + my $query_desc; + ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang, $query_desc) = parseQuery($operators, $operands, $indexes, $limits, $sort_by, $scan, $lang); # dereference my @operators = $operators ? @$operators : (); @@ -1229,7 +1262,6 @@ sub buildQuery { # initialize the variables we're passing back my $query_cgi; - my $query_desc; my $query_type; my $limit; @@ -1264,7 +1296,13 @@ sub buildQuery { return ( undef, $', $', "q=cql=$'", $', '', '', '', '', 'cql' ); } if ( $query =~ /^pqf=/ ) { - return ( undef, $', $', "q=pqf=$'", $', '', '', '', '', 'pqf' ); + if ($query_desc) { + $query_cgi = "q=$query_desc"; + } else { + $query_desc = $'; + $query_cgi = "q=pqf=$'"; + } + return ( undef, $', $', $query_cgi, $query_desc, '', '', '', '', 'pqf' ); } # pass nested queries directly diff --git a/Koha/SuggestionEngine/Plugin/AuthorityFile.pm b/Koha/SuggestionEngine/Plugin/AuthorityFile.pm index fdc41c5..7df5fa2 100644 --- a/Koha/SuggestionEngine/Plugin/AuthorityFile.pm +++ b/Koha/SuggestionEngine/Plugin/AuthorityFile.pm @@ -85,7 +85,7 @@ sub get_suggestions { # FIXME: calling into C4 require C4::AuthoritiesMarc; my ( $searchresults, $count ) = C4::AuthoritiesMarc::SearchAuthorities( - \@marclist, \@and_or, \@excluding, \@operator, + @marclist, @and_or, @excluding, @operator, @value, 0, $param->{'count'}, '', 'Relevance', 0 ); diff --git a/cataloguing/addbooks.pl b/cataloguing/addbooks.pl index 7bca2f3..7af1a71 100755 --- a/cataloguing/addbooks.pl +++ b/cataloguing/addbooks.pl @@ -70,10 +70,16 @@ if ($query) { # build query my @operands = $query; - my ( $builterror,$builtquery,$simple_query,$query_cgi,$query_desc,$limit,$limit_cgi,$limit_desc,$stopwords_removed,$query_type) = buildQuery(undef,\@operands); + + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); + unless ($QParser) { + my ( $builterror,$builtquery,$simple_query,$query_cgi,$query_desc,$limit,$limit_cgi,$limit_desc,$stopwords_removed,$query_type) = buildQuery(undef,\@operands); + $query = $builtquery; + } # find results - my ( $error, $marcresults, $total_hits ) = SimpleSearch($builtquery, $results_per_page * ($page - 1), $results_per_page); + my ( $error, $marcresults, $total_hits ) = SimpleSearch($query, $results_per_page * ($page - 1), $results_per_page); if ( defined $error ) { $template->param( error => $error ); diff --git a/cataloguing/value_builder/marc21_linking_section.pl b/cataloguing/value_builder/marc21_linking_section.pl index f317f8b..f30086e 100644 --- a/cataloguing/value_builder/marc21_linking_section.pl +++ b/cataloguing/value_builder/marc21_linking_section.pl @@ -190,7 +190,15 @@ sub plugin { my $startfrom = $query->param('startfrom'); my $resultsperpage = $query->param('resultsperpage') || 20; my $orderby; - $search = 'kw,wrdl=' . $search . ' and mc-itemtype=' . $itype if $itype; + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); + my $op; + if ($QParser) { + $op = '&&'; + } else { + $op = 'and'; + } + $search = 'kw:' . $search . " $op mc-itemtype:" . $itype if $itype; my ( $errors, $results, $total_hits ) = SimpleSearch( $search, $startfrom * $resultsperpage, $resultsperpage ); diff --git a/cataloguing/value_builder/unimarc_field_4XX.pl b/cataloguing/value_builder/unimarc_field_4XX.pl index acc0854..0202438 100755 --- a/cataloguing/value_builder/unimarc_field_4XX.pl +++ b/cataloguing/value_builder/unimarc_field_4XX.pl @@ -341,7 +341,15 @@ sub plugin { my $startfrom = $query->param('startfrom'); my $resultsperpage = $query->param('resultsperpage') || 20; my $orderby; - $search = 'kw,wrdl='.$search.' and mc-itemtype='.$itype if $itype; + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); + my $op; + if ($QParser) { + $op = '&&'; + } else { + $op = 'and'; + } + $search = 'kw:'.$search." $op mc-itemtype:".$itype if $itype; my ( $errors, $results, $total_hits ) = SimpleSearch($search, $startfrom * $resultsperpage, $resultsperpage ); if (defined $errors ) { $results = []; diff --git a/labels/label-item-search.pl b/labels/label-item-search.pl index 9b92009..7f6827e 100755 --- a/labels/label-item-search.pl +++ b/labels/label-item-search.pl @@ -66,10 +66,12 @@ my $display_columns = [ {_add => {label => "Add Item", link_fi ]; if ( $op eq "do_search" ) { + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); $idx = $query->param('idx'); $ccl_textbox = $query->param('ccl_textbox'); if ( $ccl_textbox && $idx ) { - $ccl_query = "$idx=$ccl_textbox"; + $ccl_query = "$idx:$ccl_textbox"; } $datefrom = $query->param('datefrom'); @@ -77,15 +79,26 @@ if ( $op eq "do_search" ) { if ($datefrom) { $datefrom = C4::Dates->new($datefrom); - $ccl_query .= ' and ' if $ccl_textbox; - $ccl_query .= - "acqdate,st-date-normalized,ge=" . $datefrom->output("iso"); + if ($QParser) { + $ccl_query .= ' && ' if $ccl_textbox; + $ccl_query .= + "acqdate(" . $datefrom->output("iso") . '-)'; + } else { + $ccl_query .= ' and ' if $ccl_textbox; + $ccl_query .= + "acqdate,st-date-normalized,ge=" . $datefrom->output("iso"); + } } if ($dateto) { $dateto = C4::Dates->new($dateto); - $ccl_query .= ' and ' if ( $ccl_textbox || $datefrom ); - $ccl_query .= "acqdate,st-date-normalized,le=" . $dateto->output("iso"); + if ($QParser) { + $ccl_query .= ' && ' if ( $ccl_textbox || $datefrom ); + $ccl_query .= "acqdate(-" . $dateto->output("iso") . ')'; + } else { + $ccl_query .= ' and ' if ( $ccl_textbox || $datefrom ); + $ccl_query .= "acqdate,st-date-normalized,le=" . $datefrom->output("iso"); + } } my $offset = $startfrom > 1 ? $startfrom - 1 : 0; diff --git a/misc/migration_tools/bulkmarcimport.pl b/misc/migration_tools/bulkmarcimport.pl index e0f905c..682af89 100755 --- a/misc/migration_tools/bulkmarcimport.pl +++ b/misc/migration_tools/bulkmarcimport.pl @@ -432,7 +432,15 @@ sub build_query { my $string = build_simplequery($matchingpoint,$record); push @searchstrings,$string if (length($string)>0); } - return join(" and ",@searchstrings); + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); + my $op; + if ($QParser) { + $op = '&&'; + } else { + $op = 'and'; + } + return join(" $op ",@searchstrings); } sub build_simplequery { my $element=shift; @@ -442,10 +450,18 @@ sub build_simplequery { my @searchstrings; foreach my $field ($record->field($tag)){ if (length($field->as_string("$subfields"))>0){ - push @searchstrings,"$index,wrdl=\"".$field->as_string("$subfields")."\""; + push @searchstrings,"$index:\"".$field->as_string("$subfields")."\""; } } - return join(" and ",@searchstrings); + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); + my $op; + if ($QParser) { + $op = '&&'; + } else { + $op = 'and'; + } + return join(" $op ",@searchstrings); } sub report_item_errors { my $biblionumber = shift; diff --git a/serials/subscription-bib-search.pl b/serials/subscription-bib-search.pl index 623efe2..95e4aa7 100755 --- a/serials/subscription-bib-search.pl +++ b/serials/subscription-bib-search.pl @@ -90,11 +90,19 @@ if ($op eq "do_search" && $query) { # add the itemtype limit if applicable my $itemtypelimit = $input->param('itemtypelimit'); if ( $itemtypelimit ) { - if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') { - $query .= " AND $itype_or_itemtype=$itemtypelimit"; - } else { - $query .= " AND $advanced_search_types=$itemtypelimit"; - } + my $QParser; + $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser')); + my $op; + if ($QParser) { + $op = '&&'; + } else { + $op = 'and'; + } + if (!$advanced_search_types or $advanced_search_types eq 'itemtypes') { + $query .= " $op $itype_or_itemtype:$itemtypelimit"; + } else { + $query .= " $op $advanced_search_types:$itemtypelimit"; + } } $debug && warn $query; $resultsperpage= $input->param('resultsperpage'); -- 1.7.10.4