Bugfix in modification
[koha.git] / C4 / AuthoritiesMarc.pm
1 package C4::AuthoritiesMarc;
2 # Copyright 2000-2002 Katipo Communications
3 #
4 # This file is part of Koha.
5 #
6 # Koha is free software; you can redistribute it and/or modify it under the
7 # terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
9 # version.
10 #
11 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
17 # Suite 330, Boston, MA  02111-1307 USA
18
19 use strict;
20 require Exporter;
21 use C4::Context;
22 use C4::Database;
23 use C4::Koha;
24 use MARC::Record;
25 use C4::Biblio;
26
27 use vars qw($VERSION @ISA @EXPORT);
28
29 # set the version for version checking
30 $VERSION = 0.01;
31
32 @ISA = qw(Exporter);
33 @EXPORT = qw(
34         &AUTHgettagslib
35         &AUTHfindsubfield
36         &AUTHfind_authtypecode
37
38         &AUTHaddauthority
39         &AUTHmodauthority
40         &AUTHdelauthority
41         &AUTHaddsubfield
42         &AUTHgetauthority
43         
44         &AUTHgetauth_type
45         
46         &authoritysearch
47         
48         &MARCmodsubfield
49         &AUTHhtml2marc
50         &AUTHaddword
51         &MARCaddword &MARCdelword
52         &char_decode
53  );
54
55 sub authoritysearch {
56         my ($dbh, $tags, $and_or, $excluding, $operator, $value, $offset,$length,$authtypecode) = @_;
57         # build the sql request. She will look like :
58         # select m1.bibid
59         #               from auth_subfield_table as m1, auth_subfield_table as m2
60         #               where m1.authid=m2.authid and
61         #               (m1.subfieldvalue like "Des%" and m2.subfieldvalue like "27%")
62
63         # "Normal" statements
64         my @normal_tags = ();
65         my @normal_and_or = ();
66         my @normal_operator = ();
67         my @normal_value = ();
68         # Extracts the NOT statements from the list of statements
69         for(my $i = 0 ; $i <= $#{$value} ; $i++)
70         {
71                 if(@$operator[$i] eq "contains") # if operator is contains, splits the words in separate requests
72                 {
73                         foreach my $word (split(/ /, @$value[$i]))
74                         {
75                                 unless (C4::Context->stopwords->{uc($word)}) {  #it's NOT a stopword => use it. Otherwise, ignore
76                                         my $tag = substr(@$tags[$i],0,3);
77                                         my $subf = substr(@$tags[$i],3,1);
78                                         push @normal_tags, @$tags[$i];
79                                         push @normal_and_or, "and";     # assumes "foo" and "bar" if "foo bar" is entered
80                                         push @normal_operator, @$operator[$i];
81                                         push @normal_value, $word;
82                                 }
83                         }
84                 }
85                 else
86                 {
87                         push @normal_tags, @$tags[$i];
88                         push @normal_and_or, @$and_or[$i];
89                         push @normal_operator, @$operator[$i];
90                         push @normal_value, @$value[$i];
91                 }
92         }
93
94         # Finds the basic results without the NOT requests
95         my ($sql_tables, $sql_where1, $sql_where2) = create_request($dbh,\@normal_tags, \@normal_and_or, \@normal_operator, \@normal_value);
96
97         my $sth;
98
99         if ($sql_where2) {
100                 $sth = $dbh->prepare("select distinct m1.authid from auth_header,$sql_tables where  m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where2 and ($sql_where1)");
101                 warn "Q2 : select distinct m1.authid from auth_header,$sql_tables where  m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where2 and ($sql_where1)";
102         } else {
103                 $sth = $dbh->prepare("select distinct m1.authid from auth_header,$sql_tables where  m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where1");
104                 warn "Q : select distinct m1.authid from auth_header,$sql_tables where  m1.authid=auth_header.authid and auth_header.authtypecode=? and $sql_where1";
105         }
106         $sth->execute($authtypecode);
107         my @result = ();
108         while (my ($authid) = $sth->fetchrow) {
109                         push @result,$authid;
110                 }
111
112         # we have authid list. Now, loads summary from [offset] to [offset]+[length]
113         my $counter = $offset;
114         my @finalresult = ();
115         my $oldline;
116         while (($counter <= $#result) && ($counter <= ($offset + $length))) {
117 #               warn " HERE : $counter, $#result, $offset, $length";
118                 # get MARC::Record of the authority
119                 my $record = AUTHgetauthority($dbh,$result[$counter]);
120                 # then build the summary
121                 my $authtypecode = AUTHfind_authtypecode($dbh,$result[$counter]);
122                 my $authref = getauthtype($authtypecode);
123                 my $summary = $authref->{summary};
124                 my @fields = $record->fields();
125                 foreach my $field (@fields) {
126                         my $tag = $field->tag();
127                         if ($tag<10) {
128                         } else {
129                                 my @subf = $field->subfields;
130                                 for my $i (0..$#subf) {
131                                         my $subfieldcode = $subf[$i][0];
132                                         my $subfieldvalue = $subf[$i][1];
133                                         my $tagsubf = $tag.$subfieldcode;
134                                         $summary =~ s/\[(.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue\[$1$tagsubf$2]$2$3/g;
135                                 }
136                         }
137                 }
138                 $summary =~ s/\[(.*?)]//g;
139                 $summary =~ s/\n/<br>/g;
140
141                 # find biblio MARC field using this authtypecode (to jump to biblio)
142                 my $authtypecode = AUTHfind_authtypecode($dbh,$result[$counter]);
143                 my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
144                 $sth->execute($authtypecode);
145                 my $tags_using_authtype;
146                 while (my ($tagfield) = $sth->fetchrow) {
147 #                       warn "TAG : $tagfield";
148                         $tags_using_authtype.= $tagfield."9,";
149                 }
150                 chop $tags_using_authtype;
151                 
152                 # then add a line for the template loop
153                 my %newline;
154                 $newline{summary} = $summary;
155                 $newline{authid} = $result[$counter];
156                 $newline{used} = &AUTHcount_usage($result[$counter]);
157                 $newline{biblio_fields} = $tags_using_authtype;
158                 $counter++;
159                 push @finalresult, \%newline;
160         }
161         my $nbresults = $#result + 1;
162         return (\@finalresult, $nbresults);
163 }
164
165 # Creates the SQL Request
166
167 sub create_request {
168         my ($dbh,$tags, $and_or, $operator, $value) = @_;
169
170         my $sql_tables; # will contain marc_subfield_table as m1,...
171         my $sql_where1; # will contain the "true" where
172         my $sql_where2 = "("; # will contain m1.authid=m2.authid
173         my $nb_active=0; # will contain the number of "active" entries. and entry is active is a value is provided.
174         my $nb_table=1; # will contain the number of table. ++ on each entry EXCEPT when an OR  is provided.
175
176
177         for(my $i=0; $i<=@$value;$i++) {
178                 if (@$value[$i]) {
179                         $nb_active++;
180                         if ($nb_active==1) {
181                                 if (@$operator[$i] eq "start") {
182                                         $sql_tables .= "auth_subfield_table as m$nb_table,";
183                                         $sql_where1 .= "(m1.subfieldvalue like ".$dbh->quote("@$value[$i]%");
184                                         if (@$tags[$i]) {
185                                                 $sql_where1 .=" and m1.tag+m1.subfieldcode in (@$tags[$i])";
186                                         }
187                                         $sql_where1.=")";
188                                 } elsif (@$operator[$i] eq "contains") {        
189                                 $sql_tables .= "auth_word as m$nb_table,";
190                                         $sql_where1 .= "(m1.word  like ".$dbh->quote("@$value[$i]%");
191                                         if (@$tags[$i]) {
192                                                  $sql_where1 .=" and m1.tagsubfield in (@$tags[$i])";
193                                         }
194                                         $sql_where1.=")";
195                                 } else {
196
197                                         $sql_tables .= "auth_subfield_table as m$nb_table,";
198                                         $sql_where1 .= "(m1.subfieldvalue @$operator[$i] ".$dbh->quote("@$value[$i]");
199                                         if (@$tags[$i]) {
200                                                  $sql_where1 .=" and m1.tag+m1.subfieldcode in (@$tags[$i])";
201                                         }
202                                         $sql_where1.=")";
203                                 }
204                         } else {
205                                 if (@$operator[$i] eq "start") {
206                                         $nb_table++;
207                                         $sql_tables .= "auth_subfield_table as m$nb_table,";
208                                         $sql_where1 .= "@$and_or[$i] (m$nb_table.subfieldvalue like ".$dbh->quote("@$value[$i]%");
209                                         if (@$tags[$i]) {
210                                                 $sql_where1 .=" and m$nb_table.tag+m$nb_table.subfieldcode in (@$tags[$i])";
211                                         }
212                                         $sql_where1.=")";
213                                         $sql_where2 .= "m1.authid=m$nb_table.authid and ";
214                                 } elsif (@$operator[$i] eq "contains") {
215                                         if (@$and_or[$i] eq 'and') {
216                                                 $nb_table++;
217                                                 $sql_tables .= "auth_word as m$nb_table,";
218                                                 $sql_where1 .= "@$and_or[$i] (m$nb_table.word like ".$dbh->quote("@$value[$i]%");
219                                                 if (@$tags[$i]) {
220                                                         $sql_where1 .=" and m$nb_table.tagsubfield in(@$tags[$i])";
221                                                 }
222                                                 $sql_where1.=")";
223                                                 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
224                                         } else {
225                                                 $sql_where1 .= "@$and_or[$i] (m$nb_table.word like ".$dbh->quote("@$value[$i]%");
226                                                 if (@$tags[$i]) {
227                                                         $sql_where1 .="  and m$nb_table.tag+m$nb_table.subfieldid in (@$tags[$i])";
228                                                 }
229                                                 $sql_where1.=")";
230                                                 $sql_where2 .= "m1.authid=m$nb_table.authid and ";
231                                         }
232                                 } else {
233                                         $nb_table++;
234                                         $sql_tables .= "auth_subfield_table as m$nb_table,";
235                                         $sql_where1 .= "@$and_or[$i] (m$nb_table.subfieldvalue @$operator[$i] ".$dbh->quote(@$value[$i]);
236                                         if (@$tags[$i]) {
237                                                 $sql_where1 .="  and m$nb_table.tag+m$nb_table.subfieldcode in (@$tags[$i])";
238                                         }
239                                         $sql_where2 .= "m1.authid=m$nb_table.authid and ";
240                                         $sql_where1.=")";
241                                 }
242                         }
243                 }
244         }
245
246         if($sql_where2 ne "(")  # some datas added to sql_where2, processing
247         {
248                 $sql_where2 = substr($sql_where2, 0, (length($sql_where2)-5)); # deletes the trailing ' and '
249                 $sql_where2 .= ")";
250         }
251         else    # no sql_where2 statement, deleting '('
252         {
253                 $sql_where2 = "";
254         }
255         chop $sql_tables;       # deletes the trailing ','
256         
257         return ($sql_tables, $sql_where1, $sql_where2);
258 }
259
260
261 sub AUTHcount_usage {
262         my ($authid) = @_;
263         my $dbh = C4::Context->dbh;
264         # find MARC fields using this authtype
265         my $authtypecode = AUTHfind_authtypecode($dbh,$authid);
266         my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
267         $sth->execute($authtypecode);
268         my $tags_using_authtype;
269         while (my ($tagfield) = $sth->fetchrow) {
270 #               warn "TAG : $tagfield";
271                 $tags_using_authtype.= "'".$tagfield."9',";
272         }
273         chop $tags_using_authtype;
274         if ($tags_using_authtype) {
275                 $sth = $dbh->prepare("select count(*) from marc_subfield_table where concat(tag,subfieldcode) in ($tags_using_authtype) and subfieldvalue=?");
276         } else {
277                 $sth = $dbh->prepare("select count(*) from marc_subfield_table where subfieldvalue=?");
278         }
279 #       warn "Q : select count(*) from marc_subfield_table where concat(tag,subfieldcode) in ($tags_using_authtype) and subfieldvalue=$authid";
280         $sth->execute($authid);
281         my ($result) = $sth->fetchrow;
282 #       warn "Authority $authid TOTAL USED : $result";
283         return $result;
284 }
285
286 # merging 2 authority entries. After a merge, the "from" can be deleted.
287 # sub AUTHmerge {
288 #       my ($auth_merge_from,$auth_merge_to) = @_;
289 #       my $dbh = C4::Context->dbh;
290 #       # find MARC fields using this authtype
291 #       my $authtypecode = AUTHfind_authtypecode($dbh,$authid);
292 #       # retrieve records
293 #       my $record_from = AUTHgetauthority($dbh,$auth_merge_from);
294 #       my $record_to = AUTHgetauthority($dbh,$auth_merge_to);
295 #       my $sth = $dbh->prepare("select distinct tagfield from marc_subfield_structure where authtypecode=?");
296 #       $sth->execute($authtypecode);
297 #       my $tags_using_authtype;
298 #       while (my ($tagfield) = $sth->fetchrow) {
299 #               warn "TAG : $tagfield";
300 #               $tags_using_authtype.= "'".$tagfield."9',";
301 #       }
302 #       chop $tags_using_authtype;
303 #       # now, find every biblio using this authority
304 #       $sth = $dbh->prepare("select bibid,tag,tag_indicator,tagorder from marc_subfield_table where tag+subfieldid in ($tags_using_authtype) and subfieldvalue=?");
305 #       $sth->execute($authid);
306 #       # and delete entries before recreating them
307 #       while (my ($bibid,$tag,$tag_indicator,$tagorder) = $sth->fetchrow) {
308 #               &MARCdelsubfield($dbh,$bibid,$tag);
309 #               
310 #       }
311
312 # }
313
314 sub AUTHfind_authtypecode {
315         my ($dbh,$authid) = @_;
316         my $sth = $dbh->prepare("select authtypecode from auth_header where authid=?");
317         $sth->execute($authid);
318         my ($authtypecode) = $sth->fetchrow;
319         return $authtypecode;
320 }
321  
322
323 sub AUTHgettagslib {
324         my ($dbh,$forlibrarian,$authtypecode)= @_;
325         $authtypecode="" unless $authtypecode;
326         my $sth;
327         my $libfield = ($forlibrarian eq 1)? 'liblibrarian' : 'libopac';
328         # check that framework exists
329         $sth=$dbh->prepare("select count(*) from auth_tag_structure where authtypecode=?");
330         $sth->execute($authtypecode);
331         my ($total) = $sth->fetchrow;
332         $authtypecode="" unless ($total >0);
333         $sth=$dbh->prepare("select tagfield,$libfield as lib,mandatory,repeatable from auth_tag_structure where authtypecode=? order by tagfield");
334         $sth->execute($authtypecode);
335         my ($lib,$tag,$res,$tab,$mandatory,$repeatable);
336         while ( ($tag,$lib,$mandatory,$repeatable) = $sth->fetchrow) {
337                 $res->{$tag}->{lib}=$lib;
338                 $res->{$tab}->{tab}=""; # XXX
339                 $res->{$tag}->{mandatory}=$mandatory;
340                 $res->{$tag}->{repeatable}=$repeatable;
341         }
342
343         $sth=$dbh->prepare("select tagfield,tagsubfield,$libfield as lib,tab, mandatory, repeatable,authorised_value,value_builder,seealso from auth_subfield_structure where authtypecode=? order by tagfield,tagsubfield");
344         $sth->execute($authtypecode);
345
346         my $subfield;
347         my $authorised_value;
348         my $thesaurus_category;
349         my $value_builder;
350         my $kohafield;
351         my $seealso;
352         my $hidden;
353         my $isurl;
354         while ( ($tag, $subfield, $lib, $tab, $mandatory, $repeatable,$authorised_value,$value_builder,$seealso) = $sth->fetchrow) {
355                 $res->{$tag}->{$subfield}->{lib}=$lib;
356                 $res->{$tag}->{$subfield}->{tab}=$tab;
357                 $res->{$tag}->{$subfield}->{mandatory}=$mandatory;
358                 $res->{$tag}->{$subfield}->{repeatable}=$repeatable;
359                 $res->{$tag}->{$subfield}->{authorised_value}=$authorised_value;
360                 $res->{$tag}->{$subfield}->{thesaurus_category}=$thesaurus_category;
361                 $res->{$tag}->{$subfield}->{value_builder}=$value_builder;
362                 $res->{$tag}->{$subfield}->{seealso}=$seealso;
363                 $res->{$tag}->{$subfield}->{hidden}=$hidden;
364                 $res->{$tag}->{$subfield}->{isurl}=$isurl;
365         }
366         return $res;
367 }
368
369 sub AUTHaddauthority {
370 # pass the MARC::Record to this function, and it will create the records in the marc tables
371         my ($dbh,$record,$authid,$authtypecode) = @_;
372         my @fields=$record->fields();
373 #       warn "IN AUTHaddauthority $authid => ".$record->as_formatted;
374 # adding main table, and retrieving authid
375 # if authid is sent, then it's not a true add, it's only a re-add, after a delete (ie, a mod)
376 # if authid empty => true add, find a new authid number
377         unless ($authid) {
378                 $dbh->do("lock tables auth_header WRITE,auth_subfield_table WRITE, auth_word WRITE, stopwords READ");
379                 my $sth=$dbh->prepare("insert into auth_header (datecreated,authtypecode) values (now(),?)");
380                 $sth->execute($authtypecode);
381                 $sth=$dbh->prepare("select max(authid) from auth_header");
382                 $sth->execute;
383                 ($authid)=$sth->fetchrow;
384                 $sth->finish;
385         }
386         my $fieldcount=0;
387         # now, add subfields...
388         foreach my $field (@fields) {
389                 $fieldcount++;
390                 if ($field->tag() <10) {
391                                 &AUTHaddsubfield($dbh,$authid,
392                                                 $field->tag(),
393                                                 '',
394                                                 $fieldcount,
395                                                 '',
396                                                 1,
397                                                 $field->data()
398                                                 );
399                 } else {
400                         my @subfields=$field->subfields();
401                         foreach my $subfieldcount (0..$#subfields) {
402                                 &AUTHaddsubfield($dbh,$authid,
403                                                 $field->tag(),
404                                                 $field->indicator(1).$field->indicator(2),
405                                                 $fieldcount,
406                                                 $subfields[$subfieldcount][0],
407                                                 $subfieldcount+1,
408                                                 $subfields[$subfieldcount][1]
409                                                 );
410                         }
411                 }
412         }
413         $dbh->do("unlock tables");
414         return $authid;
415 }
416
417
418 sub AUTHaddsubfield {
419 # Add a new subfield to a tag into the DB.
420         my ($dbh,$authid,$tagid,$tag_indicator,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalues) = @_;
421         # if not value, end of job, we do nothing
422         if (length($subfieldvalues) ==0) {
423                 return;
424         }
425         if (not($subfieldcode)) {
426                 $subfieldcode=' ';
427         }
428         my @subfieldvalues = split /\|/,$subfieldvalues;
429         foreach my $subfieldvalue (@subfieldvalues) {
430                 my $sth=$dbh->prepare("insert into auth_subfield_table (authid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue) values (?,?,?,?,?,?,?)");
431                 $sth->execute($authid,(sprintf "%03s",$tagid),$tagorder,$tag_indicator,$subfieldcode,$subfieldorder,$subfieldvalue);
432                 if ($sth->errstr) {
433                         warn "ERROR ==> insert into auth_subfield_table (authid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue) values ($authid,$tagid,$tagorder,$tag_indicator,$subfieldcode,$subfieldorder,$subfieldvalue)\n";
434                 }
435                 &AUTHaddword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalue);
436         }
437 }
438
439 sub AUTHgetauthority {
440 # Returns MARC::Record of the biblio passed in parameter.
441     my ($dbh,$authid)=@_;
442     my $record = MARC::Record->new();
443 #---- TODO : the leader is missing
444         $record->leader('                        ');
445     my $sth=$dbh->prepare("select authid,subfieldid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue
446                                  from auth_subfield_table
447                                  where authid=? order by tag,tagorder,subfieldcode
448                          ");
449         $sth->execute($authid);
450         my $prevtagorder=1;
451         my $prevtag='XXX';
452         my $previndicator;
453         my $field; # for >=10 tags
454         my $prevvalue; # for <10 tags
455         while (my $row=$sth->fetchrow_hashref) {
456                 if ($row->{tagorder} ne $prevtagorder || $row->{tag} ne $prevtag) {
457                         $previndicator.="  ";
458                         if ($prevtag <10) {
459                         $record->add_fields((sprintf "%03s",$prevtag),$prevvalue) unless $prevtag eq "XXX"; # ignore the 1st loop
460                         } else {
461                                 $record->add_fields($field) unless $prevtag eq "XXX";
462                         }
463                         undef $field;
464                         $prevtagorder=$row->{tagorder};
465                         $prevtag = $row->{tag};
466                         $previndicator=$row->{tag_indicator};
467                         if ($row->{tag}<10) {
468                                 $prevvalue = $row->{subfieldvalue};
469                         } else {
470                                 $field = MARC::Field->new((sprintf "%03s",$prevtag), substr($row->{tag_indicator}.'  ',0,1), substr($row->{tag_indicator}.'  ',1,1), $row->{'subfieldcode'}, $row->{'subfieldvalue'} );
471                         }
472                 } else {
473                         if ($row->{tag} <10) {
474                                 $record->add_fields((sprintf "%03s",$row->{tag}), $row->{'subfieldvalue'});
475                         } else {
476                                 $field->add_subfields($row->{'subfieldcode'}, $row->{'subfieldvalue'} );
477                         }
478                         $prevtag= $row->{tag};
479                         $previndicator=$row->{tag_indicator};
480                 }
481         }
482         # the last has not been included inside the loop... do it now !
483         if ($prevtag ne "XXX") { # check that we have found something. Otherwise, prevtag is still XXX and we
484                                                 # must return an empty record, not make MARC::Record fail because we try to
485                                                 # create a record with XXX as field :-(
486                 if ($prevtag <10) {
487                         $record->add_fields($prevtag,$prevvalue);
488                 } else {
489         #               my $field = MARC::Field->new( $prevtag, "", "", %subfieldlist);
490                         $record->add_fields($field);
491                 }
492         }
493         return $record;
494 }
495
496 sub AUTHgetauth_type {
497         my ($authtypecode) = @_;
498         my $dbh=C4::Context->dbh;
499         my $sth=$dbh->prepare("select * from auth_types where authtypecode=?");
500         $sth->execute($authtypecode);
501         return $sth->fetchrow_hashref;
502 }
503 sub AUTHmodauthority {
504         my ($dbh,$authid,$record,$delete)=@_;
505         my $oldrecord=&AUTHgetauthority($dbh,$authid);
506         if ($oldrecord eq $record) {
507                 return;
508         }
509 # 1st delete the authority,
510 # 2nd recreate it
511         &AUTHdelauthority($dbh,$authid,1);
512         &AUTHaddauthority($dbh,$record,$authid,AUTHfind_authtypecode($dbh,$authid));
513         # FIXME : modify the authority in biblio too.
514 }
515
516 sub AUTHdelauthority {
517         my ($dbh,$authid,$keep_biblio) = @_;
518 # if the keep_biblio is set to 1, then authority entries in biblio are preserved.
519 # This flag is set when the delauthority is called by modauthority
520 # due to a too complex structure of MARC (repeatable fields and subfields),
521 # the best solution for a modif is to delete / recreate the record.
522
523         my $record = AUTHgetauthority($dbh,$authid);
524         $dbh->do("delete from auth_header where authid=$authid") unless $keep_biblio;
525         $dbh->do("delete from auth_subfield_table where authid=$authid");
526         $dbh->do("delete from auth_word where authid=$authid");
527 # FIXME : delete or not in biblio tables (depending on $keep_biblio flag)
528 }
529
530 sub AUTHmodsubfield {
531 # Subroutine changes a subfield value given a subfieldid.
532         my ($dbh, $subfieldid, $subfieldvalue )=@_;
533         $dbh->do("lock tables auth_subfield_table WRITE");
534         my $sth=$dbh->prepare("update auth_subfield_table set subfieldvalue=? where subfieldid=?");
535         $sth->execute($subfieldvalue, $subfieldid);
536         $dbh->do("unlock tables");
537         $sth->finish;
538         $sth=$dbh->prepare("select authid,tag,tagorder,subfieldcode,subfieldid,subfieldorder from auth_subfield_table where subfieldid=?");
539         $sth->execute($subfieldid);
540         my ($authid,$tagid,$tagorder,$subfieldcode,$x,$subfieldorder) = $sth->fetchrow;
541         $subfieldid=$x;
542         &AUTHdelword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder);
543         &AUTHaddword($dbh,$authid,$tagid,$tagorder,$subfieldcode,$subfieldorder,$subfieldvalue);
544         return($subfieldid, $subfieldvalue);
545 }
546
547 sub AUTHfindsubfield {
548     my ($dbh,$authid,$tag,$subfieldcode,$subfieldorder,$subfieldvalue) = @_;
549     my $resultcounter=0;
550     my $subfieldid;
551     my $lastsubfieldid;
552     my $query="select subfieldid from auth_subfield_table where authid=? and tag=? and subfieldcode=?";
553     my @bind_values = ($authid,$tag, $subfieldcode);
554     if ($subfieldvalue) {
555         $query .= " and subfieldvalue=?";
556         push(@bind_values,$subfieldvalue);
557     } else {
558         if ($subfieldorder<1) {
559             $subfieldorder=1;
560         }
561         $query .= " and subfieldorder=?";
562         push(@bind_values,$subfieldorder);
563     }
564     my $sti=$dbh->prepare($query);
565     $sti->execute(@bind_values);
566     while (($subfieldid) = $sti->fetchrow) {
567         $resultcounter++;
568         $lastsubfieldid=$subfieldid;
569     }
570     if ($resultcounter>1) {
571                 # Error condition.  Values given did not resolve into a unique record.  Don't know what to edit
572                 # should rarely occur (only if we use subfieldvalue with a value that exists twice, which is strange)
573                 return -1;
574     } else {
575                 return $lastsubfieldid;
576     }
577 }
578
579 sub AUTHfindsubfieldid {
580         my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
581         my $sth=$dbh->prepare("select subfieldid from auth_subfield_table
582                                 where authid=? and tag=? and tagorder=?
583                                         and subfieldcode=? and subfieldorder=?");
584         $sth->execute($authid,$tag,$tagorder,$subfield,$subfieldorder);
585         my ($res) = $sth->fetchrow;
586         unless ($res) {
587                 $sth=$dbh->prepare("select subfieldid from auth_subfield_table
588                                 where authid=? and tag=? and tagorder=?
589                                         and subfieldcode=?");
590                 $sth->execute($authid,$tag,$tagorder,$subfield);
591                 ($res) = $sth->fetchrow;
592         }
593     return $res;
594 }
595
596 sub AUTHfind_authtypecode {
597         my ($dbh,$authid) = @_;
598         my $sth = $dbh->prepare("select authtypecode from auth_header where authid=?");
599         $sth->execute($authid);
600         my ($authtypecode) = $sth->fetchrow;
601         return $authtypecode;
602 }
603
604 sub AUTHdelsubfield {
605 # delete a subfield for $authid / tag / tagorder / subfield / subfieldorder
606     my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
607     $dbh->do("delete from auth_subfield_table where authid='$authid' and
608                         tag='$tag' and tagorder='$tagorder'
609                         and subfieldcode='$subfield' and subfieldorder='$subfieldorder'
610                         ");
611 }
612
613 sub AUTHhtml2marc {
614         my ($dbh,$rtags,$rsubfields,$rvalues,%indicators) = @_;
615         my $prevtag = -1;
616         my $record = MARC::Record->new();
617 #       my %subfieldlist=();
618         my $prevvalue; # if tag <10
619         my $field; # if tag >=10
620         for (my $i=0; $i< @$rtags; $i++) {
621                 # rebuild MARC::Record
622                 if (@$rtags[$i] ne $prevtag) {
623                         if ($prevtag < 10) {
624                                 if ($prevvalue) {
625                                         $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
626                                 }
627                         } else {
628                                 if ($field) {
629                                         $record->add_fields($field);
630                                 }
631                         }
632                         $indicators{@$rtags[$i]}.='  ';
633                         if (@$rtags[$i] <10) {
634                                 $prevvalue= @$rvalues[$i];
635                         } else {
636                                 $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
637                         }
638                         $prevtag = @$rtags[$i];
639                 } else {
640                         if (@$rtags[$i] <10) {
641                                 $prevvalue=@$rvalues[$i];
642                         } else {
643                                 if (@$rvalues[$i]) {
644                                         $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
645                                 }
646                         }
647                         $prevtag= @$rtags[$i];
648                 }
649         }
650         # the last has not been included inside the loop... do it now !
651         $record->add_fields($field);
652 #       warn $record->as_formatted;
653         return $record;
654 }
655
656 sub AUTHaddword {
657 # split a subfield string and adds it into the word table.
658 # removes stopwords
659     my ($dbh,$authid,$tag,$tagorder,$subfieldid,$subfieldorder,$sentence) =@_;
660     $sentence =~ s/(\.|\?|\:|\!|\'|,|\-|\"|\(|\)|\[|\]|\{|\})/ /g;
661     my @words = split / /,$sentence;
662     my $stopwords= C4::Context->stopwords;
663     my $sth=$dbh->prepare("insert into auth_word (authid, tagsubfield, tagorder, subfieldorder, word, sndx_word)
664                         values (?,concat(?,?),?,?,?,soundex(?))");
665     foreach my $word (@words) {
666 # we record only words longer than 2 car and not in stopwords hash
667         if (length($word)>2 and !($stopwords->{uc($word)})) {
668             $sth->execute($authid,$tag,$subfieldid,$tagorder,$subfieldorder,$word,$word);
669             if ($sth->err()) {
670                 warn "ERROR ==> insert into auth_word (authid, tagsubfield, tagorder, subfieldorder, word, sndx_word) values ($authid,concat($tag,$subfieldid),$tagorder,$subfieldorder,$word,soundex($word))\n";
671             }
672         }
673     }
674 }
675
676 sub AUTHdelword {
677 # delete words. this sub deletes all the words from a sentence. a subfield modif is done by a delete then a add
678     my ($dbh,$authid,$tag,$tagorder,$subfield,$subfieldorder) = @_;
679     my $sth=$dbh->prepare("delete from auth_word where authid=? and tagsubfield=concat(?,?) and tagorder=? and subfieldorder=?");
680     $sth->execute($authid,$tag,$subfield,$tagorder,$subfieldorder);
681 }
682
683 sub char_decode {
684         # converts ISO 5426 coded string to ISO 8859-1
685         # sloppy code : should be improved in next issue
686         my ($string,$encoding) = @_ ;
687         $_ = $string ;
688 #       $encoding = C4::Context->preference("marcflavour") unless $encoding;
689         if ($encoding eq "UNIMARC") {
690                 s/\xe1/Æ/gm ;
691                 s/\xe2/Ð/gm ;
692                 s/\xe9/Ø/gm ;
693                 s/\xec/þ/gm ;
694                 s/\xf1/æ/gm ;
695                 s/\xf3/ð/gm ;
696                 s/\xf9/ø/gm ;
697                 s/\xfb/ß/gm ;
698                 s/\xc1\x61/à/gm ;
699                 s/\xc1\x65/è/gm ;
700                 s/\xc1\x69/ì/gm ;
701                 s/\xc1\x6f/ò/gm ;
702                 s/\xc1\x75/ù/gm ;
703                 s/\xc1\x41/À/gm ;
704                 s/\xc1\x45/È/gm ;
705                 s/\xc1\x49/Ì/gm ;
706                 s/\xc1\x4f/Ò/gm ;
707                 s/\xc1\x55/Ù/gm ;
708                 s/\xc2\x41/Á/gm ;
709                 s/\xc2\x45/É/gm ;
710                 s/\xc2\x49/Í/gm ;
711                 s/\xc2\x4f/Ó/gm ;
712                 s/\xc2\x55/Ú/gm ;
713                 s/\xc2\x59/Ý/gm ;
714                 s/\xc2\x61/á/gm ;
715                 s/\xc2\x65/é/gm ;
716                 s/\xc2\x69/í/gm ;
717                 s/\xc2\x6f/ó/gm ;
718                 s/\xc2\x75/ú/gm ;
719                 s/\xc2\x79/ý/gm ;
720                 s/\xc3\x41/Â/gm ;
721                 s/\xc3\x45/Ê/gm ;
722                 s/\xc3\x49/Î/gm ;
723                 s/\xc3\x4f/Ô/gm ;
724                 s/\xc3\x55/Û/gm ;
725                 s/\xc3\x61/â/gm ;
726                 s/\xc3\x65/ê/gm ;
727                 s/\xc3\x69/î/gm ;
728                 s/\xc3\x6f/ô/gm ;
729                 s/\xc3\x75/û/gm ;
730                 s/\xc4\x41/Ã/gm ;
731                 s/\xc4\x4e/Ñ/gm ;
732                 s/\xc4\x4f/Õ/gm ;
733                 s/\xc4\x61/ã/gm ;
734                 s/\xc4\x6e/ñ/gm ;
735                 s/\xc4\x6f/õ/gm ;
736                 s/\xc8\x45/Ë/gm ;
737                 s/\xc8\x49/Ï/gm ;
738                 s/\xc8\x65/ë/gm ;
739                 s/\xc8\x69/ï/gm ;
740                 s/\xc8\x76/ÿ/gm ;
741                 s/\xc9\x41/Ä/gm ;
742                 s/\xc9\x4f/Ö/gm ;
743                 s/\xc9\x55/Ü/gm ;
744                 s/\xc9\x61/ä/gm ;
745                 s/\xc9\x6f/ö/gm ;
746                 s/\xc9\x75/ü/gm ;
747                 s/\xca\x41/Å/gm ;
748                 s/\xca\x61/å/gm ;
749                 s/\xd0\x43/Ç/gm ;
750                 s/\xd0\x63/ç/gm ;
751                 # this handles non-sorting blocks (if implementation requires this)
752                 $string = nsb_clean($_) ;
753         } elsif ($encoding eq "USMARC" || $encoding eq "MARC21") {
754                 if(/[\xc1-\xff]/) {
755                         s/\xe1\x61/à/gm ;
756                         s/\xe1\x65/è/gm ;
757                         s/\xe1\x69/ì/gm ;
758                         s/\xe1\x6f/ò/gm ;
759                         s/\xe1\x75/ù/gm ;
760                         s/\xe1\x41/À/gm ;
761                         s/\xe1\x45/È/gm ;
762                         s/\xe1\x49/Ì/gm ;
763                         s/\xe1\x4f/Ò/gm ;
764                         s/\xe1\x55/Ù/gm ;
765                         s/\xe2\x41/Á/gm ;
766                         s/\xe2\x45/É/gm ;
767                         s/\xe2\x49/Í/gm ;
768                         s/\xe2\x4f/Ó/gm ;
769                         s/\xe2\x55/Ú/gm ;
770                         s/\xe2\x59/Ý/gm ;
771                         s/\xe2\x61/á/gm ;
772                         s/\xe2\x65/é/gm ;
773                         s/\xe2\x69/í/gm ;
774                         s/\xe2\x6f/ó/gm ;
775                         s/\xe2\x75/ú/gm ;
776                         s/\xe2\x79/ý/gm ;
777                         s/\xe3\x41/Â/gm ;
778                         s/\xe3\x45/Ê/gm ;
779                         s/\xe3\x49/Î/gm ;
780                         s/\xe3\x4f/Ô/gm ;
781                         s/\xe3\x55/Û/gm ;
782                         s/\xe3\x61/â/gm ;
783                         s/\xe3\x65/ê/gm ;
784                         s/\xe3\x69/î/gm ;
785                         s/\xe3\x6f/ô/gm ;
786                         s/\xe3\x75/û/gm ;
787                         s/\xe4\x41/Ã/gm ;
788                         s/\xe4\x4e/Ñ/gm ;
789                         s/\xe4\x4f/Õ/gm ;
790                         s/\xe4\x61/ã/gm ;
791                         s/\xe4\x6e/ñ/gm ;
792                         s/\xe4\x6f/õ/gm ;
793                         s/\xe8\x45/Ë/gm ;
794                         s/\xe8\x49/Ï/gm ;
795                         s/\xe8\x65/ë/gm ;
796                         s/\xe8\x69/ï/gm ;
797                         s/\xe8\x76/ÿ/gm ;
798                         s/\xe9\x41/Ä/gm ;
799                         s/\xe9\x4f/Ö/gm ;
800                         s/\xe9\x55/Ü/gm ;
801                         s/\xe9\x61/ä/gm ;
802                         s/\xe9\x6f/ö/gm ;
803                         s/\xe9\x75/ü/gm ;
804                         s/\xea\x41/Å/gm ;
805                         s/\xea\x61/å/gm ;
806                         # this handles non-sorting blocks (if implementation requires this)
807                         $string = nsb_clean($_) ;
808                 }
809         }
810         return($string) ;
811 }
812
813 sub nsb_clean {
814         my $NSB = '\x88' ;              # NSB : begin Non Sorting Block
815         my $NSE = '\x89' ;              # NSE : Non Sorting Block end
816         # handles non sorting blocks
817         my ($string) = @_ ;
818         $_ = $string ;
819         s/$NSB/(/gm ;
820         s/[ ]{0,1}$NSE/) /gm ;
821         $string = $_ ;
822         return($string) ;
823 }
824
825 END { }       # module clean-up code here (global destructor)
826
827 =back
828
829 =head1 AUTHOR
830
831 Koha Developement team <info@koha.org>
832
833 Paul POULAIN paul.poulain@free.fr
834
835 =cut
836
837 # $Id$
838 # $Log$
839 # Revision 1.7  2004/09/23 16:13:00  tipaul
840 # Bugfix in modification
841 #
842 # Revision 1.6  2004/08/18 16:00:24  tipaul
843 # fixes for authorities management
844 #
845 # Revision 1.5  2004/07/05 13:37:22  doxulting
846 # First step for working authorities
847 #
848 # Revision 1.4  2004/06/22 11:35:37  tipaul
849 # removing % at the beginning of a string to avoid loooonnnngggg searchs
850 #
851 # Revision 1.3  2004/06/17 08:02:13  tipaul
852 # merging tag & subfield in auth_word for better perfs
853 #
854 # Revision 1.2  2004/06/10 08:29:01  tipaul
855 # MARC authority management (continued)
856 #
857 # Revision 1.1  2004/06/07 07:35:01  tipaul
858 # MARC authority management package
859 #