X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FBreeding.pm;h=7b3dbc5874623cc51e941394da7f9445db84fba1;hb=a195708e97159831184a081dabae007bfe00e14a;hp=fa3af82475acaf72cae6b0eaac257e9c364b79c1;hpb=168871403c3bc8df91d6be65caba4bdd49745085;p=koha-ffzg.git diff --git a/C4/Breeding.pm b/C4/Breeding.pm index fa3af82475..7b3dbc5874 100644 --- a/C4/Breeding.pm +++ b/C4/Breeding.pm @@ -5,40 +5,38 @@ package C4::Breeding; # # This file is part of Koha. # -# Koha is free software; you can redistribute it and/or modify it under the -# terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. # -# Koha is distributed in the hope that it will be useful, but WITHOUT ANY -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. # -# You should have received a copy of the GNU General Public License along -# with Koha; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use strict; use warnings; -use C4::Biblio; -use C4::Koha; -use C4::Charset; +use C4::Biblio qw(TransformMarcToKoha); +use C4::Koha qw( GetVariationsOfISBN ); +use C4::Charset qw( MarcToUTF8Record SetUTF8Flag ); use MARC::File::USMARC; -use C4::ImportBatch; -use C4::AuthoritiesMarc; #GuessAuthTypeCode, FindDuplicateAuthority +use MARC::Field; +use C4::ImportBatch qw( GetZ3950BatchId AddBiblioToBatch AddAuthToBatch ); +use C4::AuthoritiesMarc qw( GuessAuthTypeCode ); use C4::Languages; use Koha::Database; -use Koha::XSLT_Handler; - -use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); +use Koha::XSLT::Base; +our (@ISA, @EXPORT_OK); BEGIN { - # set the version for version checking - $VERSION = 3.07.00.049; - require Exporter; - @ISA = qw(Exporter); - @EXPORT = qw(&BreedingSearch &Z3950Search &Z3950SearchAuth); + require Exporter; + @ISA = qw(Exporter); + @EXPORT_OK = qw(BreedingSearch Z3950Search Z3950SearchAuth); } =head1 NAME @@ -49,7 +47,7 @@ C4::Breeding : module to add biblios to import_records via =head1 SYNOPSIS Z3950Search($pars, $template); - ($count, @results) = &BreedingSearch($title,$isbn,$random); + ($count, @results) = &BreedingSearch($title,$isbn); =head1 DESCRIPTION @@ -58,10 +56,8 @@ cataloguing reservoir features. =head2 BreedingSearch -($count, @results) = &BreedingSearch($title,$isbn,$random); -C<$title> contains the title, -C<$isbn> contains isbn or issn, -C<$random> contains the random seed from a z3950 search. +($count, @results) = &BreedingSearch($term); +C<$term> contains the term to search, it will be searched as title,author, or isbn C<$count> is the number of items in C<@results>. C<@results> is an array of references-to-hash; the keys are the items from the C and @@ -70,40 +66,31 @@ C tables of the Koha database. =cut sub BreedingSearch { - my ($search,$isbn,$z3950random) = @_; + my ($term) = @_; my $dbh = C4::Context->dbh; my $count = 0; my ($query,@bind); my $sth; my @results; + my $authortitle = $term; + $authortitle =~ s/(\s+)/\%/g; #Replace spaces with wildcard + $authortitle = "%" . $authortitle . "%"; #Add wildcard to start and end of string # normalise ISBN like at import - $isbn = C4::Koha::GetNormalizedISBN($isbn); - - $query = "SELECT import_record_id, file_name, isbn, title, author - FROM import_biblios + my @isbns = C4::Koha::GetVariationsOfISBN($term); + + $query = "SELECT import_biblios.import_record_id, + import_batches.file_name, + import_biblios.isbn, + import_biblios.title, + import_biblios.author, + import_batches.upload_timestamp + FROM import_biblios JOIN import_records USING (import_record_id) JOIN import_batches USING (import_batch_id) - WHERE "; - if ($z3950random) { - $query .= "z3950random = ?"; - @bind=($z3950random); - } else { - @bind=(); - if (defined($search) && length($search)>0) { - $search =~ s/(\s+)/\%/g; - $query .= "title like ? OR author like ?"; - push(@bind,"%$search%", "%$search%"); - } - if ($#bind!=-1 && defined($isbn) && length($isbn)>0) { - $query .= " and "; - } - if (defined($isbn) && length($isbn)>0) { - $query .= "isbn like ?"; - push(@bind,"$isbn%"); - } - } - $sth = $dbh->prepare($query); + WHERE title LIKE ? OR author LIKE ? OR isbn IN (" . join(',',('?') x @isbns) . ")"; + @bind=( $authortitle, $authortitle, @isbns ); + $sth = $dbh->prepare($query); $sth->execute(@bind); while (my $data = $sth->fetchrow_hashref) { $results[$count] = $data; @@ -149,7 +136,7 @@ sub Z3950Search { my $s = 0; my $imported=0; - my ( $zquery, $squery ) = _build_query( $pars ); + my ( $zquery, $squery ) = _bib_build_query( $pars ); my $schema = Koha::Database->new()->schema(); my $rs = $schema->resultset('Z3950server')->search( @@ -158,15 +145,19 @@ sub Z3950Search { ); my @servers = $rs->all; foreach my $server ( @servers ) { + my $server_zquery = $zquery; + if(my $attributes = $server->{attributes}){ + $server_zquery = "$attributes $zquery"; + } $oConnection[$s] = _create_connection( $server ); $oResult[$s] = $server->{servertype} eq 'zed'? - $oConnection[$s]->search_pqf( $zquery ): - $oConnection[$s]->search(new ZOOM::Query::CQL( + $oConnection[$s]->search_pqf( $server_zquery ): + $oConnection[$s]->search(ZOOM::Query::CQL->new( _translate_query( $server, $squery ))); $s++; } - my $xslh = Koha::XSLT_Handler->new; + my $xslh = Koha::XSLT::Base->new; my $nremaining = $s; while ( $nremaining-- ) { @@ -229,13 +220,34 @@ sub Z3950Search { ); } -sub _build_query { +sub _auth_build_query { + my ( $pars ) = @_; + + my $qry_build = { + nameany => '@attr 1=1002 "#term" ', + authorany => '@attr 1=1003 "#term" ', + authorcorp => '@attr 1=2 "#term" ', + authorpersonal => '@attr 1=1 "#term" ', + authormeetingcon => '@attr 1=3 "#term" ', + subject => '@attr 1=21 "#term" ', + subjectsubdiv => '@attr 1=47 "#term" ', + title => '@attr 1=4 "#term" ', + uniformtitle => '@attr 1=6 "#term" ', + srchany => '@attr 1=1016 "#term" ', + controlnumber => '@attr 1=12 "#term" ', + }; + + return _build_query( $pars, $qry_build ); +} + +sub _bib_build_query { + my ( $pars ) = @_; my $qry_build = { isbn => '@attr 1=7 @attr 5=1 "#term" ', issn => '@attr 1=8 @attr 5=1 "#term" ', - title => '@attr 1=4 #term ', + title => '@attr 1=4 "#term" ', author => '@attr 1=1003 "#term" ', dewey => '@attr 1=16 "#term" ', subject => '@attr 1=21 "#term" ', @@ -244,12 +256,22 @@ sub _build_query { controlnumber => '@attr 1=12 "#term" ', srchany => '@attr 1=1016 "#term" ', stdid => '@attr 1=1007 "#term" ', + publicationyear => '@attr 1=31 "#term" ' }; + return _build_query( $pars, $qry_build ); +} + +sub _build_query { + + my ( $pars, $qry_build ) = @_; + my $zquery=''; my $squery=''; my $nterms=0; - foreach my $k ( keys %$pars ) { + foreach my $k ( sort keys %$pars ) { + #note that the sort keys forces an identical result under Perl 5.18 + #one of the unit tests is based on that assumption if( ( my $val=$pars->{$k} ) && $qry_build->{$k} ) { $qry_build->{$k} =~ s/#term/$val/g; $zquery .= $qry_build->{$k}; @@ -270,6 +292,7 @@ sub _handle_one_result { if( $servhref->{servertype} eq 'sru' ) { $marcrecord= MARC::Record->new_from_xml( $raw, 'UTF-8', $servhref->{syntax} ); + $marcrecord->encoding('UTF-8'); } else { ($marcrecord) = MarcToUTF8Record($raw, C4::Context->preference('marcflavour'), $servhref->{encoding} // "iso-5426" ); #ignores charset return values } @@ -278,21 +301,20 @@ sub _handle_one_result { ( $marcrecord, $error ) = _do_xslt_proc($marcrecord, $servhref, $xslh); my $batch_id = GetZ3950BatchId($servhref->{servername}); - my $breedingid = AddBiblioToBatch($batch_id, $seq, $marcrecord, 'UTF-8', 0, 0); - #FIXME passing 0 for z3950random - #Will eliminate this unused field in a followup report + my $breedingid = AddBiblioToBatch($batch_id, $seq, $marcrecord, 'UTF-8', 0); #Last zero indicates: no update for batch record counts - - #call to TransformMarcToKoha replaced by next call - #we only need six fields from the marc record my $row; - $row = _add_rowdata( - { - biblionumber => $bib, - server => $servhref->{servername}, - breedingid => $breedingid, - }, $marcrecord) if $breedingid; + if( $breedingid ){ + my @kohafields = ('biblio.title','biblio.author','biblioitems.isbn','biblioitems.lccn','biblioitems.editionstatement'); + push @kohafields, C4::Context->preference('marcflavour') eq "MARC21" ? 'biblio.copyrightdate' : 'biblioitems.publicationyear'; + $row = C4::Biblio::TransformMarcToKoha({ record => $marcrecord, kohafields => \@kohafields, limit_table => 'no_items' }); + $row->{biblionumber} = $bib; + $row->{server} = $servhref->{servername}; + $row->{breedingid} = $breedingid; + $row->{isbn}=_isbn_replace($row->{isbn}); + $row = _add_custom_field_rowdata($row, $marcrecord); + } return ( $row, $error ); } @@ -316,28 +338,57 @@ sub _do_xslt_proc { if( !$xslh->err ) { return MARC::Record->new_from_xml($xml, 'UTF-8'); } else { - return ( $marc, 'xslt_err' ); #original record in case of errors + return ( $marc, $xslh->err ); #original record in case of errors } } -sub _add_rowdata { - my ($row, $record)=@_; - my %fetch= ( - title => 'biblio.title', - author => 'biblio.author', - isbn =>'biblioitems.isbn', - lccn =>'biblioitems.lccn', #LC control number (not call number) - edition =>'biblioitems.editionstatement', - date => 'biblio.copyrightdate', #MARC21 - date2 => 'biblioitems.publicationyear', #UNIMARC - ); - foreach my $k (keys %fetch) { - my ($t, $f)= split '\.', $fetch{$k}; - $row= C4::Biblio::TransformMarcToKohaOneField($t, $f, $record, $row); - $row->{$k}= $row->{$f} if $k ne $f; +sub _add_custom_field_rowdata +{ + my ( $row, $record ) = @_; + my $pref_newtags = C4::Context->preference('AdditionalFieldsInZ3950ResultSearch'); + my $pref_flavour = C4::Context->preference('MarcFlavour'); + + $pref_newtags =~ s/^\s+|\s+$//g; + $pref_newtags =~ s/\h+/ /g; + + my @addnumberfields; + + foreach my $field (split /\,/, $pref_newtags) { + $field =~ s/^\s+|\s+$//g ; # trim whitespace + my ($tag, $subtags) = split(/\$/, $field); + + if ( $record->field($tag) ) { + my @content = (); + + for my $marcfield ($record->field($tag)) { + if ( $subtags ) { + my $str = ''; + for my $code (split //, $subtags) { + if ( $marcfield->subfield($code) ) { + $str .= $marcfield->subfield($code) . ' '; + } + } + if ( not $str eq '') { + push @content, $str; + } + } elsif ( $tag == 10 ) { + push @content, ( $pref_flavour eq "MARC21" ? $marcfield->data : $marcfield->as_string ); + } elsif ( $tag < 10 ) { + push @content, $marcfield->data(); + } else { + push @content, $marcfield->as_string(); + } + } + + if ( @content ) { + $row->{$field} = \@content; + push( @addnumberfields, $field ); + } + } } - $row->{date}//= $row->{date2}; - $row->{isbn}=_isbn_replace($row->{isbn}); + + $row->{'addnumberfields'} = \@addnumberfields; + return $row; } @@ -352,7 +403,7 @@ sub _isbn_replace { sub _create_connection { my ( $server ) = @_; - my $option1= new ZOOM::Options(); + my $option1= ZOOM::Options->new(); $option1->option( 'async' => 1 ); $option1->option( 'elementSetName', 'F' ); $option1->option( 'preferredRecordSyntax', $server->{syntax} ); @@ -371,7 +422,6 @@ sub _create_connection { $option1->option( 'user', $server->{userid} ) if $server->{userid}; $option1->option( 'password', $server->{password} ) if $server->{password}; } - my $obj= ZOOM::Connection->create($option1); if( $server->{servertype} eq 'sru' ) { my $host= $server->{host}; @@ -412,78 +462,30 @@ sub _translate_query { #SRU query adjusted per server cf. srufields column =head2 ImportBreedingAuth -ImportBreedingAuth($marcrecords,$overwrite_auth,$filename,$encoding,$z3950random,$batch_type); +ImportBreedingAuth( $marcrecord, $filename, $encoding, $heading ); - ImportBreedingAuth imports MARC records in the reservoir (import_records table). - ImportBreedingAuth is based on the ImportBreeding subroutine. + ImportBreedingAuth imports MARC records in the reservoir (import_records table) or returns their id if they already exist. =cut sub ImportBreedingAuth { - my ($marcrecords,$overwrite_auth,$filename,$encoding,$z3950random,$batch_type) = @_; - my @marcarray = split /\x1D/, $marcrecords; - + my ( $marcrecord, $filename, $encoding, $heading ) = @_; my $dbh = C4::Context->dbh; my $batch_id = GetZ3950BatchId($filename); my $searchbreeding = $dbh->prepare("select import_record_id from import_auths where control_number=? and authorized_heading=?"); -# $encoding = C4::Context->preference("marcflavour") unless $encoding; - # fields used for import results - my $imported=0; - my $alreadyindb = 0; - my $alreadyinfarm = 0; - my $notmarcrecord = 0; - my $breedingid; - for (my $i=0;$i<=$#marcarray;$i++) { - my ($marcrecord, $charset_result, $charset_errors); - ($marcrecord, $charset_result, $charset_errors) = - MarcToUTF8Record($marcarray[$i]."\x1D", C4::Context->preference("marcflavour"), $encoding); - - # Normalize the record so it doesn't have separated diacritics - SetUTF8Flag($marcrecord); - - if (scalar($marcrecord->fields()) == 0) { - $notmarcrecord++; - } else { - my $heading; - $heading = C4::AuthoritiesMarc::GetAuthorizedHeading({ record => $marcrecord }); - - my $heading_authtype_code; - $heading_authtype_code = GuessAuthTypeCode($marcrecord); + my $controlnumber = $marcrecord->field('001')->data; - my $controlnumber; - $controlnumber = $marcrecord->field('001')->data; + # Normalize the record so it doesn't have separated diacritics + SetUTF8Flag($marcrecord); - #Check if the authority record already exists in the database... - my ($duplicateauthid,$duplicateauthvalue); - if ($marcrecord && $heading_authtype_code) { - ($duplicateauthid,$duplicateauthvalue) = FindDuplicateAuthority( $marcrecord, $heading_authtype_code); - } + $searchbreeding->execute($controlnumber,$heading); + my ($breedingid) = $searchbreeding->fetchrow; - if ($duplicateauthid && $overwrite_auth ne 2) { - #If the authority record exists and $overwrite_auth doesn't equal 2, then mark it as already in the DB - $alreadyindb++; - } else { - if ($controlnumber && $heading) { - $searchbreeding->execute($controlnumber,$heading); - ($breedingid) = $searchbreeding->fetchrow; - } - if ($breedingid && $overwrite_auth eq '0') { - $alreadyinfarm++; - } else { - if ($breedingid && $overwrite_auth eq '1') { - ModAuthorityInBatch($breedingid, $marcrecord); - } else { - my $import_id = AddAuthToBatch($batch_id, $imported, $marcrecord, $encoding, $z3950random); - $breedingid = $import_id; - } - $imported++; - } - } - } - } - return ($notmarcrecord,$alreadyindb,$alreadyinfarm,$imported,$breedingid); + return $breedingid if $breedingid; + $breedingid = AddAuthToBatch($batch_id, 0, $marcrecord, $encoding); + return $breedingid; } =head2 Z3950SearchAuth @@ -503,125 +505,52 @@ sub Z3950SearchAuth { my $dbh = C4::Context->dbh; my @id= @{$pars->{id}}; - my $random= $pars->{random}; my $page= $pars->{page}; - my $nameany= $pars->{nameany}; - my $authorany= $pars->{authorany}; - my $authorpersonal= $pars->{authorpersonal}; - my $authorcorp= $pars->{authorcorp}; - my $authormeetingcon= $pars->{authormeetingcon}; - my $title= $pars->{title}; - my $uniformtitle= $pars->{uniformtitle}; - my $subject= $pars->{subject}; - my $subjectsubdiv= $pars->{subjectsubdiv}; - my $srchany= $pars->{srchany}; my $show_next = 0; my $total_pages = 0; - my $attr = ''; - my $host; - my $server; - my $database; - my $port; - my $marcdata; my @encoding; my @results; - my $count; - my $record; my @serverhost; - my @servername; my @breeding_loop = (); - my @oConnection; my @oResult; my @errconn; + my @servers; my $s = 0; my $query; my $nterms=0; - if ($nameany) { - $query .= " \@attr 1=1002 \"$nameany\" "; #Any name (this includes personal, corporate, meeting/conference authors, and author names in subject headings) - #This attribute is supported by both the Library of Congress and Libraries Australia 08/05/2013 - $nterms++; - } - - if ($authorany) { - $query .= " \@attr 1=1003 \"$authorany\" "; #Author-name (this includes personal, corporate, meeting/conference authors, but not author names in subject headings) - #This attribute is not supported by the Library of Congress, but is supported by Libraries Australia 08/05/2013 - $nterms++; - } - - if ($authorcorp) { - $query .= " \@attr 1=2 \"$authorcorp\" "; #1005 is another valid corporate author attribute... - $nterms++; - } - - if ($authorpersonal) { - $query .= " \@attr 1=1 \"$authorpersonal\" "; #1004 is another valid personal name attribute... - $nterms++; - } - - if ($authormeetingcon) { - $query .= " \@attr 1=3 \"$authormeetingcon\" "; #1006 is another valid meeting/conference name attribute... - $nterms++; - } - - if ($subject) { - $query .= " \@attr 1=21 \"$subject\" "; - $nterms++; - } - - if ($subjectsubdiv) { - $query .= " \@attr 1=47 \"$subjectsubdiv\" "; - $nterms++; - } - - if ($title) { - $query .= " \@attr 1=4 \"$title\" "; #This is a regular title search. 1=6 will give just uniform titles - $nterms++; - } - - if ($uniformtitle) { - $query .= " \@attr 1=6 \"$uniformtitle\" "; #This is the uniform title search - $nterms++; - } - - if($srchany) { - $query .= " \@attr 1=1016 \"$srchany\" "; - $nterms++; - } - - for my $i (1..$nterms-1) { - $query = "\@and " . $query; - } - + my $marcflavour = C4::Context->preference('marcflavour'); + my $marc_type = $marcflavour eq 'UNIMARC' ? 'UNIMARCAUTH' : $marcflavour; + my $authid= $pars->{authid}; + my ( $zquery, $squery ) = _auth_build_query( $pars ); foreach my $servid (@id) { my $sth = $dbh->prepare("select * from z3950servers where id=?"); $sth->execute($servid); - while ( $server = $sth->fetchrow_hashref ) { - my $option1 = new ZOOM::Options(); - $option1->option( 'async' => 1 ); - $option1->option( 'elementSetName', 'F' ); - $option1->option( 'databaseName', $server->{db} ); - $option1->option( 'user', $server->{userid} ) if $server->{userid}; - $option1->option( 'password', $server->{password} ) if $server->{password}; - $option1->option( 'preferredRecordSyntax', $server->{syntax} ); - $option1->option( 'timeout', $server->{timeout} ) if $server->{timeout}; - $oConnection[$s] = create ZOOM::Connection($option1); - $oConnection[$s]->connect( $server->{host}, $server->{port} ); - $serverhost[$s] = $server->{host}; - $servername[$s] = $server->{name}; + while ( my $server = $sth->fetchrow_hashref ) { + $oConnection[$s] = _create_connection( $server ); + + if ( $server->{servertype} eq 'zed' ) { + my $server_zquery = $zquery; + if ( my $attributes = $server->{attributes} ) { + $server_zquery = "$attributes $zquery"; + } + $oResult[$s] = $oConnection[$s]->search_pqf( $server_zquery ); + } + else { + $oResult[$s] = $oConnection[$s]->search( + ZOOM::Query::CQL->new(_translate_query( $server, $squery )) + ); + } $encoding[$s] = ($server->{encoding}?$server->{encoding}:"iso-5426"); + $servers[$s] = $server; $s++; - } ## while fetch + } ## while fetch } # foreach my $nremaining = $s; - for ( my $z = 0 ; $z < $s ; $z++ ) { - $oResult[$z] = $oConnection[$z]->search_pqf($query); - } - while ( $nremaining-- ) { my $k; my $event; @@ -632,7 +561,7 @@ sub Z3950SearchAuth { if ( $k != 0 ) { $k--; - my ($error, $errmsg, $addinfo, $diagset)= $oConnection[$k]->error_x(); + my ($error )= $oConnection[$k]->error_x(); #ignores errmsg, addinfo, diagset if ($error) { if ($error =~ m/^(10000|10007)$/ ) { push(@errconn, {'server' => $serverhost[$k]}); @@ -653,23 +582,30 @@ sub Z3950SearchAuth { $marcdata = $rec->raw(); my ($charset_result, $charset_errors); - ($marcrecord, $charset_result, $charset_errors)= MarcToUTF8Record($marcdata, C4::Context->preference('marcflavour'), $encoding[$k]); - + if( $servers[$k]->{servertype} eq 'sru' ) { + $marcrecord = MARC::Record->new_from_xml( $marcdata, 'UTF-8', $servers[$k]->{syntax} ); + $marcrecord->encoding('UTF-8'); + } else { + ( $marcrecord, $charset_result, $charset_errors ) = MarcToUTF8Record( $marcdata, $marc_type, $encoding[$k] ); + } my $heading; my $heading_authtype_code; $heading_authtype_code = GuessAuthTypeCode($marcrecord); + next if ( not defined $heading_authtype_code ) ; + $heading = C4::AuthoritiesMarc::GetAuthorizedHeading({ record => $marcrecord }); - my ($notmarcrecord, $alreadyindb, $alreadyinfarm, $imported, $breedingid)= ImportBreedingAuth( $marcdata, 2, $serverhost[$k], $encoding[$k], $random, 'z3950' ); + my $breedingid = ImportBreedingAuth( $marcrecord, $serverhost[$k], $encoding[$k], $heading ); my %row_data; - $row_data{server} = $servername[$k]; + $row_data{server} = $servers[$k]->{'servername'}; $row_data{breedingid} = $breedingid; $row_data{heading} = $heading; + $row_data{authid} = $authid; $row_data{heading_code} = $heading_authtype_code; push( @breeding_loop, \%row_data ); } else { - push(@breeding_loop,{'server'=>$servername[$k],'title'=>join(': ',$oConnection[$k]->error_x()),'breedingid'=>-1}); + push(@breeding_loop,{'server'=>$servers[$k]->{'servername'},'title'=>join(': ',$oConnection[$k]->error_x()),'breedingid'=>-1,'authid'=>-1}); } } } #if $numresults @@ -691,7 +627,7 @@ sub Z3950SearchAuth { $oConnection[$_]->destroy(); } - my @servers = (); + @servers = (); foreach my $id (@id) { push @servers, {id => $id}; }