a little speed tweak here, setting "SET FOREIGN_KEY_CHECKS = 0" *before* clearing...
[koha.git] / misc / migration_tools / bulkmarcimport.pl
1 #!/usr/bin/perl
2 # Import an iso2709 file into Koha 3
3
4 use strict;
5 # use warnings;
6 BEGIN {
7     # find Koha's Perl modules
8     # test carefully before changing this
9     use FindBin;
10     eval { require "$FindBin::Bin/../kohalib.pl" };
11 }
12
13 # Koha modules used
14 use MARC::File::USMARC;
15 # Uncomment the line below and use MARC::File::XML again when it works better.
16 # -- thd
17 # use MARC::File::XML;
18 use MARC::Record;
19 use MARC::Batch;
20 use MARC::Charset;
21
22 use C4::Context;
23 use C4::Biblio;
24 use C4::Charset;
25 use C4::Items;
26 use Unicode::Normalize;
27 use Time::HiRes qw(gettimeofday);
28 use Getopt::Long;
29 binmode(STDOUT, ":utf8");
30
31 use Getopt::Long;
32
33 my ( $input_marc_file, $number) = ('',0);
34 my ($version, $delete, $test_parameter, $skip_marc8_conversion, $char_encoding, $verbose, $commit, $fk_off,$format);
35
36 $|=1;
37
38 GetOptions(
39     'commit:f'    => \$commit,
40     'file:s'    => \$input_marc_file,
41     'n:f' => \$number,
42     'h' => \$version,
43     'd' => \$delete,
44     't' => \$test_parameter,
45     's' => \$skip_marc8_conversion,
46     'c:s' => \$char_encoding,
47     'v:s' => \$verbose,
48     'fk' => \$fk_off,
49     'm:s' => \$format,
50 );
51
52 if ($version || ($input_marc_file eq '')) {
53     print <<EOF
54 small script to import an iso2709 file into Koha.
55 parameters :
56 \th : this version/help screen
57 \tfile /path/to/file/to/dump : the file to import
58 \tv : verbose mode. 1 means "some infos", 2 means "MARC dumping"
59 \tfk : Turn off foreign key checks during import.
60 \tn : the number of records to import. If missing, all the file is imported
61 \tcommit : the number of records to wait before performing a 'commit' operation
62 \tt : test mode : parses the file, saying what he would do, but doing nothing.
63 \ts : skip automatic conversion of MARC-8 to UTF-8.  This option is 
64 \t    provided for debugging.
65 \tc : the characteristic MARC flavour. At the moment, only MARC21 and UNIMARC 
66 \tsupported. MARC21 by default.
67 \td : delete EVERYTHING related to biblio in koha-DB before import  :tables :
68 \t\tbiblio, \tbiblioitems,\titems
69 IMPORTANT : don't use this script before you've entered and checked your MARC parameters tables twice (or more!).
70 Otherwise, the import won't work correctly and you will get invalid data.
71
72 SAMPLE : 
73 \t\$ export KOHA_CONF=/etc/koha.conf
74 \t\$ perl misc/migration_tools/bulkmarcimport.pl -d -commit 1000 -file /home/jmf/koha.mrc -n 3000
75 EOF
76 ;#'
77 exit;
78 }
79
80 my $dbh = C4::Context->dbh;
81
82 # save the CataloguingLog property : we don't want to log a bulkmarcimport. It will slow the import & 
83 # will create problems in the action_logs table, that can't handle more than 1 entry per second per user.
84 my $CataloguingLog = C4::Context->preference('CataloguingLog');
85 $dbh->do("UPDATE systempreferences SET value=0 WHERE variable='CataloguingLog'");
86
87 if ($fk_off) {
88         $dbh->do("SET FOREIGN_KEY_CHECKS = 0");
89 }
90
91
92 if ($delete) {
93     print "deleting biblios\n";
94     $dbh->do("truncate biblio");
95     $dbh->do("truncate biblioitems");
96     $dbh->do("truncate items");
97     $dbh->do("truncate zebraqueue");
98 }
99
100
101
102 if ($test_parameter) {
103     print "TESTING MODE ONLY\n    DOING NOTHING\n===============\n";
104 }
105
106 my $marcFlavour = C4::Context->preference('marcflavour') || 'MARC21';
107
108 print "Characteristic MARC flavour: $marcFlavour\n" if $verbose;
109 my $starttime = gettimeofday;
110 my $batch;
111 if ($format =~ /XML/i) {
112     $batch = MARC::Batch->new( 'XML', $input_marc_file );
113 } else {
114     $batch = MARC::Batch->new( 'USMARC', $input_marc_file );
115 }
116 $batch->warnings_off();
117 $batch->strict_off();
118 my $i=0;
119 my $commitnum = 50;
120
121 if ($commit) {
122
123 $commitnum = $commit;
124
125 }
126
127 $dbh->{AutoCommit} = 0;
128 RECORD: while ( my $record = $batch->next() ) {
129     $i++;
130     print ".";
131     print "\r$i" unless $i % 100;
132
133     if ($record->encoding() eq 'MARC-8' and not $skip_marc8_conversion) {
134         # FIXME update condition
135         my ($guessed_charset, $charset_errors);
136         ($record, $guessed_charset, $charset_errors) = MarcToUTF8Record($record, $marcFlavour);
137         if ($guessed_charset eq 'failed') {
138             warn "ERROR: failed to perform character conversion for record $i\n";
139             next RECORD;            
140         }
141     }
142
143     unless ($test_parameter) {
144         my ( $biblionumber, $biblioitemnumber, $itemnumbers_ref, $errors_ref );
145         eval { ( $biblionumber, $biblioitemnumber ) = AddBiblio($record, '', { defer_marc_save => 1 }) };
146         if ( $@ ) {
147             warn "ERROR: Adding biblio $biblionumber failed: $@\n";
148             next RECORD;
149         } 
150         eval { ( $itemnumbers_ref, $errors_ref ) = AddItemBatchFromMarc( $record, $biblionumber, $biblioitemnumber, '' ); };
151         if ( $@ ) {
152             warn "ERROR: Adding items to bib $biblionumber failed: $@\n";
153             # if we failed because of an exception, assume that 
154             # the MARC columns in biblioitems were not set.
155             ModBiblioMarc( $record, $biblionumber, '' );
156             next RECORD;
157         } 
158         if ($#{ $errors_ref } > -1) { 
159             report_item_errors($biblionumber, $errors_ref);
160         }
161
162         $dbh->commit() if (0 == $i % $commitnum);
163     }
164     last if $i == $number;
165 }
166 $dbh->commit();
167
168
169 if ($fk_off) {
170         $dbh->do("SET FOREIGN_KEY_CHECKS = 1");
171 }
172
173 # restore CataloguingLog
174 $dbh->do("UPDATE systempreferences SET value=$CataloguingLog WHERE variable='CataloguingLog'");
175
176 my $timeneeded = gettimeofday - $starttime;
177 print "\n$i MARC records done in $timeneeded seconds\n";
178
179 exit 0;
180
181 sub report_item_errors {
182     my $biblionumber = shift;
183     my $errors_ref = shift;
184
185     foreach my $error (@{ $errors_ref }) {
186         my $msg = "Item not added (bib $biblionumber, item tag #$error->{'item_sequence'}, barcode $error->{'item_barcode'}): ";
187         my $error_code = $error->{'error_code'};
188         $error_code =~ s/_/ /g;
189         $msg .= "$error_code $error->{'error_information'}";
190         print $msg, "\n";
191     }
192 }