Zebra perl API following changes in zebraapi.c/.h (all functions returning
[idzebra-moved-to-github.git] / perl / lib / IDZebra / Session.pm
1 # $Id: Session.pm,v 1.18 2003-07-07 10:59:33 pop Exp $
2
3 # Zebra perl API header
4 # =============================================================================
5 package IDZebra::Session;
6
7 use strict;
8 use warnings;
9 use Carp;
10
11 BEGIN {
12     use IDZebra;
13     use Scalar::Util;
14     use IDZebra::Logger qw(:flags :calls);
15     use IDZebra::Resultset;
16     use IDZebra::ScanList;
17     use IDZebra::RetrievalRecord;
18     require Exporter;
19     our $VERSION = do { my @r = (q$Revision: 1.18 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; 
20     our @ISA = qw(IDZebra::Logger Exporter);
21     our @EXPORT = qw (TRANS_RW TRANS_RO);
22 }
23
24 use constant TRANS_RW => 1;
25 use constant TRANS_RO => 0;
26
27 1;
28 # -----------------------------------------------------------------------------
29 # Class constructors, destructor
30 # -----------------------------------------------------------------------------
31 sub new {
32     my ($proto, %args) = @_;
33     my $class = ref($proto) || $proto;
34     my $self = {};
35     $self->{args} = \%args;
36     
37     bless ($self, $class);
38     $self->{cql_ct} = undef;
39     $self->{cql_mapfile} = "";
40     return ($self);
41
42     $self->{databases} = {};
43 }
44
45 sub start_service {
46     my ($self, %args) = @_;
47
48     my $zs;
49     unless (defined($self->{zs})) {
50         if (defined($args{'configFile'})) {
51             $self->{zs} = IDZebra::start($args{'configFile'});
52         } else {
53             $self->{zs} = IDZebra::start("zebra.cfg");
54         }
55     }
56 }
57
58 sub stop_service {
59     my ($self) = @_;
60     if (defined($self->{zs})) {
61         IDZebra::stop($self->{zs}) if ($self->{zs});    
62         $self->{zs} = undef;
63     }
64 }
65
66
67 sub open {
68     my ($proto,%args) = @_;
69     my $self = {};
70
71     if (ref($proto)) { $self = $proto; } else { 
72         $self = $proto->new(%args);
73     }
74
75     unless (%args) {
76         %args = %{$self->{args}};
77     }
78
79     $self->start_service(%args);
80
81     unless (defined($self->{zs})) {
82         croak ("Falied to open zebra service");
83     }    
84
85     unless (defined($self->{zh})) {
86         $self->{zh}=IDZebra::open($self->{zs}); 
87     }   
88
89     # Reset result set counter
90     $self->{rscount} = 0;
91
92     # This is needed in order to somehow initialize the service
93     $self->databases("Default");
94
95     # Load the default configuration
96     $self->group(%args);
97
98
99     # Set shadow usage
100     my $shadow = defined($args{shadow}) ? $args{shadow} : 0;
101     $self->shadow($shadow);
102     
103     $self->{odr_input} = IDZebra::odr_createmem($IDZebra::ODR_DECODE);
104     $self->{odr_output} = IDZebra::odr_createmem($IDZebra::ODR_ENCODE);
105
106     return ($self);
107 }
108
109 sub checkzh {
110     my ($self) = @_;
111     unless (defined($self->{zh})) {
112         croak ("Zebra session is not opened");
113     }
114 }
115
116 sub close {
117     my ($self) = @_;
118
119     if ($self->{zh}) {
120
121         my $stats = 0; 
122         # Delete all resulsets
123         my $r = IDZebra::deleteResultSet($self->{zh},
124                                          1, #Z_DeleteRequest_all,
125                                          0,[],
126                                          $stats);
127
128         while (IDZebra::trans_no($self->{zh}) > 0) {
129             logf (LOG_WARN,"Explicitly closing transaction with session");
130             $self->end_trans;
131         }
132
133         IDZebra::close($self->{zh});
134         $self->{zh} = undef;
135     }
136     
137     if ($self->{odr_input}) {
138         IDZebra::odr_reset($self->{odr_input});
139         IDZebra::odr_destroy($self->{odr_input});
140         $self->{odr_input} = undef;  
141     }
142
143     if ($self->{odr_output}) {
144         IDZebra::odr_reset($self->{odr_output});
145         IDZebra::odr_destroy($self->{odr_output});
146         $self->{odr_output} = undef;  
147     }
148
149     $self->stop_service;
150 }
151
152 sub DESTROY {
153     my ($self) = @_;
154     logf (LOG_LOG,"DESTROY $self");
155     $self->close; 
156
157     if (defined ($self->{cql_ct})) {
158       IDZebra::cql_transform_close($self->{cql_ct});
159     }
160
161 }
162 # -----------------------------------------------------------------------------
163 # Record group selection  This is a bit nasty... but used at many places 
164 # -----------------------------------------------------------------------------
165 sub group {
166     my ($self,%args) = @_;
167     $self->checkzh;
168     if ($#_ > 0) {
169         $self->{rg} = $self->_makeRecordGroup(%args);
170         $self->_selectRecordGroup($self->{rg});
171     }
172     return($self->{rg});
173 }
174
175 sub selectRecordGroup {
176     my ($self, $groupName) = @_;
177     $self->checkzh;
178     $self->{rg} = $self->_getRecordGroup($groupName);
179     $self->_selectRecordGroup($self->{rg});
180 }
181
182 sub _displayRecordGroup {
183     my ($self, $rg) = @_;
184     print STDERR "-----\n";
185     foreach my $key qw (groupName 
186                         databaseName 
187                         path recordId 
188                         recordType 
189                         flagStoreData 
190                         flagStoreKeys 
191                         flagRw 
192                         fileVerboseLimit 
193                         databaseNamePath 
194                         explainDatabase 
195                         followLinks) {
196         print STDERR "$key:",$rg->{$key},"\n";
197     }
198 }
199
200 sub _cloneRecordGroup {
201     my ($self, $orig) = @_;
202     my $rg = IDZebra::recordGroup->new();
203     my $r = IDZebra::init_recordGroup($rg);
204     foreach my $key qw (groupName 
205                         databaseName 
206                         path 
207                         recordId 
208                         recordType 
209                         flagStoreData 
210                         flagStoreKeys 
211                         flagRw 
212                         fileVerboseLimit 
213                         databaseNamePath 
214                         explainDatabase 
215                         followLinks) {
216         $rg->{$key} = $orig->{$key} if ($orig->{$key});
217     }
218     return ($rg);
219 }
220
221 sub _getRecordGroup {
222     my ($self, $groupName, $ext) = @_;
223     my $rg = IDZebra::recordGroup->new();
224     my $r = IDZebra::init_recordGroup($rg);
225     $rg->{groupName} = $groupName if ($groupName ne "");  
226     $ext = "" unless ($ext);
227     $r = IDZebra::res_get_recordGroup($self->{zh}, $rg, $ext);
228     return ($rg);
229 }
230
231 sub _makeRecordGroup {
232     my ($self, %args) = @_;
233     my $rg;
234
235     my @keys = keys(%args);
236     unless ($#keys >= 0) {
237         return ($self->{rg});
238     }
239
240     if ($args{groupName}) {
241         $rg = $self->_getRecordGroup($args{groupName});
242     } else {
243         $rg = $self->_cloneRecordGroup($self->{rg});
244     }
245     $self->_setRecordGroupOptions($rg, %args);
246     return ($rg);
247 }
248
249 sub _setRecordGroupOptions {
250     my ($self, $rg, %args) = @_;
251
252     foreach my $key qw (databaseName 
253                         path 
254                         recordId 
255                         recordType 
256                         flagStoreData 
257                         flagStoreKeys 
258                         flagRw 
259                         fileVerboseLimit 
260                         databaseNamePath 
261                         explainDatabase 
262                         followLinks) {
263         if (defined ($args{$key})) {
264             $rg->{$key} = $args{$key};
265         }
266     }
267 }
268 sub _selectRecordGroup {
269     my ($self, $rg) = @_;
270
271     my $r = IDZebra::set_group($self->{zh}, $rg);
272     my $dbName;
273     unless ($dbName = $rg->{databaseName}) {
274         $dbName = 'Default';
275     }
276     unless ($self->databases($dbName)) {
277         croak("Fatal error selecting database $dbName");
278     }
279 }
280 # -----------------------------------------------------------------------------
281 # Selecting databases for search (and also for updating - internally)
282 # -----------------------------------------------------------------------------
283 sub databases {
284     my ($self, @databases) = @_;
285
286     $self->checkzh;
287
288     unless ($#_ >0) {
289         return (keys(%{$self->{databases}}));
290     }
291
292     my %tmp;
293     my $changed = 0;
294     foreach my $db (@databases) {
295         $tmp{$db}++;
296         next if ($self->{databases}{$db});
297         $changed++;
298     }
299
300     foreach my $db (keys (%{$self->{databases}})) {
301         $changed++ unless ($tmp{$db});
302     }
303
304     if ($changed) {
305
306         delete ($self->{databases});
307         foreach my $db (@databases) {
308             $self->{databases}{$db}++;
309         }
310
311         if (IDZebra::select_databases($self->{zh}, 
312                                                 ($#databases + 1), 
313                                                 \@databases)) {
314             logf(LOG_FATAL, 
315                  "Could not select database(s) %s errCode=%d",
316                  join(",",@databases),
317                  $self->errCode());
318             return (0);
319         } else {
320             logf(LOG_LOG,"Database(s) selected: %s",join(",",@databases));
321         }
322     }
323     return (keys(%{$self->{databases}}));
324 }
325
326 # -----------------------------------------------------------------------------
327 # Error handling
328 # -----------------------------------------------------------------------------
329 sub errCode {
330     my ($self) = @_;
331     return(IDZebra::errCode($self->{zh}));
332 }
333
334 sub errString {
335     my ($self) = @_;
336     return(IDZebra::errString($self->{zh}));
337 }
338
339 sub errAdd {
340     my ($self) = @_;
341     return(IDZebra::errAdd($self->{zh}));
342 }
343
344 # -----------------------------------------------------------------------------
345 # Transaction stuff
346 # -----------------------------------------------------------------------------
347 sub begin_trans {
348     my ($self, $m) = @_;
349     $m = TRANS_RW unless (defined ($m));
350     if (my $err = IDZebra::begin_trans($self->{zh},$m)) {
351         if ($self->errCode == 2) {
352             croak ("TRANS_RW not allowed within TRANS_RO");
353         } else {
354             croak("Error starting transaction; code:".
355                   $self->errCode . " message: " . $self->errString);
356         }
357     }
358 }
359
360 sub end_trans {
361     my ($self) = @_;
362     $self->checkzh;
363     my $stat = IDZebra::ZebraTransactionStatus->new();
364     IDZebra::end_trans($self->{zh}, $stat);
365     return ($stat);
366 }
367
368 sub shadow {
369     my ($self, $value) = @_;
370     $self->checkzh;
371     if ($#_ > 0) { 
372         $value = 0 unless (defined($value));
373         my $r =IDZebra::set_shadow_enable($self->{zh},$value); 
374     }
375     return (IDZebra::get_shadow_enable($self->{zh}));
376 }
377
378 sub commit {
379     my ($self) = @_;
380     $self->checkzh;
381     if ($self->shadow) {
382         return(IDZebra::commit($self->{zh}));
383     }
384 }
385
386 # -----------------------------------------------------------------------------
387 # We don't really need that...
388 # -----------------------------------------------------------------------------
389 sub odr_reset {
390     my ($self, $name) = @_;
391     if ($name !~/^(input|output)$/) {
392         croak("Undefined ODR '$name'");
393     }
394   IDZebra::odr_reset($self->{"odr_$name"});
395 }
396
397 # -----------------------------------------------------------------------------
398 # Init/compact
399 # -----------------------------------------------------------------------------
400 sub init {
401     my ($self) = @_;
402     $self->checkzh;
403     return(IDZebra::init($self->{zh}));
404 }
405
406 sub compact {
407     my ($self) = @_;
408     $self->checkzh;
409     return(IDZebra::compact($self->{zh}));
410 }
411
412 sub update {
413     my ($self, %args) = @_;
414     $self->checkzh;
415     my $rg = $self->_update_args(%args);
416     $self->_selectRecordGroup($rg);
417     $self->begin_trans;
418     IDZebra::repository_update($self->{zh});
419     $self->_selectRecordGroup($self->{rg});
420     $self->end_trans;
421 }
422
423 sub delete {
424     my ($self, %args) = @_;
425     $self->checkzh;
426     my $rg = $self->_update_args(%args);
427     $self->_selectRecordGroup($rg);
428     $self->begin_trans;
429     IDZebra::repository_delete($self->{zh});
430     $self->_selectRecordGroup($self->{rg});
431     $self->end_trans;
432 }
433
434 sub show {
435     my ($self, %args) = @_;
436     $self->checkzh;
437     my $rg = $self->_update_args(%args);
438     $self->_selectRecordGroup($rg);
439     $self->begin_trans;
440     IDZebra::repository_show($self->{zh});
441     $self->_selectRecordGroup($self->{rg});
442     $self->end_trans;
443 }
444
445 sub _update_args {
446     my ($self, %args) = @_;
447     my $rg = $self->_makeRecordGroup(%args);
448     $self->_selectRecordGroup($rg);
449     return ($rg);
450 }
451
452 # -----------------------------------------------------------------------------
453 # Per record update
454 # -----------------------------------------------------------------------------
455 sub insert_record {
456     my ($self, %args) = @_;
457     $self->checkzh;
458     my @args = $self->_record_update_args(%args);
459     my $stat = IDZebra::insert_record($self->{zh}, @args);
460     my $sysno = $args[2]; $stat = -1 * $stat if ($stat > 0);
461     return $stat ? $stat : $$sysno;
462     if ($stat) { return ($stat); } else { return $sysno};
463 }
464
465 sub update_record {
466     my ($self, %args) = @_;
467     $self->checkzh;
468     my @args = $self->_record_update_args(%args);
469     my $stat = IDZebra::update_record($self->{zh}, @args);
470     my $sysno = $args[2]; $stat = -1 * $stat if ($stat > 0);
471     return $stat ? $stat : $$sysno;
472     if ($stat) { return ($stat); } else { return $$sysno};
473 }
474
475 sub delete_record {
476     my ($self, %args) = @_;
477     $self->checkzh;
478     my @args = $self->_record_update_args(%args);
479     my $stat = IDZebra::delete_record($self->{zh}, @args);
480     my $sysno = $args[2]; $stat = -1 * $stat if ($stat > 0);
481     return $stat ? $stat : $$sysno;
482 }
483
484 sub _record_update_args {
485     my ($self, %args) = @_;
486
487     my $sysno   = $args{sysno}      ? $args{sysno}      : 0;
488     my $match   = $args{match}      ? $args{match}      : "";
489     my $rectype = $args{recordType} ? $args{recordType} : "";
490     my $fname   = $args{file}       ? $args{file}       : "<no file>";
491     my $force   = $args{force}      ? $args{force}      : 0;
492
493     my $buff;
494
495     if ($args{data}) {
496         $buff = $args{data};
497     } 
498     elsif ($args{file}) {
499         CORE::open (F, $args{file}) || warn ("Cannot open $args{file}");
500         $buff = join('',(<F>));
501         CORE::close (F);
502     }
503     my $len = length($buff);
504
505     delete ($args{sysno});
506     delete ($args{match});
507     delete ($args{recordType});
508     delete ($args{file});
509     delete ($args{data});
510     delete ($args{force});
511
512     my $rg = $self->_makeRecordGroup(%args);
513
514     # If no record type is given, then try to find it out from the
515     # file extension;
516     unless ($rectype) {
517         if (my ($ext) = $fname =~ /\.(\w+)$/) {
518             my $rg2 = $self->_getRecordGroup($rg->{groupName},$ext);
519             $rectype = $rg2->{recordType};
520         } 
521     }
522
523     $rg->{databaseName} = "Default" unless ($rg->{databaseName});
524
525     unless ($rectype) {
526         $rectype="";
527     }
528     return ($rg, $rectype, \$sysno, $match, $fname, $buff, $len, $force);
529 }
530
531 # -----------------------------------------------------------------------------
532 # CQL stuff
533 sub cqlmap {
534     my ($self,$mapfile) = @_;
535     if ($#_ > 0) {
536         if ($self->{cql_mapfile} ne $mapfile) {
537             unless (-f $mapfile) {
538                 croak("Cannot find $mapfile");
539             }
540             if (defined ($self->{cql_ct})) {
541               IDZebra::cql_transform_close($self->{cql_ct});
542             }
543             $self->{cql_ct} = IDZebra::cql_transform_open_fname($mapfile);
544             $self->{cql_mapfile} = $mapfile;
545         }
546     }
547     return ($self->{cql_mapfile});
548 }
549
550 sub cql2pqf {
551     my ($self, $cqlquery) = @_;
552     unless (defined($self->{cql_ct})) {
553         croak("CQL map file is not specified yet.");
554     }
555     my $res = "\0" x 2048;
556     my $r = IDZebra::cql2pqf($self->{cql_ct}, $cqlquery, $res, 2048);
557     if ($r) {
558 #       carp ("Error transforming CQL query: '$cqlquery', status:$r");
559     }
560     $res=~s/\0.+$//g;
561     return ($res,$r); 
562 }
563
564
565 # -----------------------------------------------------------------------------
566 # Search 
567 # -----------------------------------------------------------------------------
568 sub search {
569     my ($self, %args) = @_;
570
571     $self->checkzh;
572
573     if ($args{cqlmap}) { $self->cqlmap($args{cqlmap}); }
574
575     my $query;
576     if ($args{pqf}) {
577         $query = $args{pqf};
578     }
579     elsif ($args{cql}) {
580         my $cqlstat;
581         ($query, $cqlstat) =  $self->cql2pqf($args{cql});
582         unless ($query) {
583             croak ("Failed to transform query: '$args{cql}', ".
584                    "status: ($cqlstat)");
585         }
586     }
587     unless ($query) {
588         croak ("No query given to search");
589     }
590
591     my @origdbs;
592
593     if ($args{databases}) {
594         @origdbs = $self->databases;
595         $self->databases(@{$args{databases}});
596     }
597
598     my $rsname = $args{rsname} ? $args{rsname} : $self->_new_setname;
599
600     my $rs = $self->_search_pqf($query, $rsname);
601
602     if ($args{databases}) {
603         $self->databases(@origdbs);
604     }
605
606     if ($args{sort}) {
607         if ($rs->errCode) {
608             carp("Sort skipped due to search error: ".
609                  $rs->errCode);
610         } else {
611             $rs->sort($args{sort});
612         }
613     }
614
615     return ($rs);
616 }
617
618 sub _new_setname {
619     my ($self) = @_;
620     return ("set_".$self->{rscount}++);
621 }
622
623 sub _search_pqf {
624     my ($self, $query, $setname) = @_;
625
626
627     my $hits = 0;
628
629     my $res = IDZebra::search_PQF($self->{zh},
630                                    $query,
631                                    $setname,
632                                    \$hits);
633
634     my $rs  = IDZebra::Resultset->new($self,
635                                       name        => $setname,
636                                       recordCount => $hits,
637                                       errCode     => $self->errCode,
638                                       errString   => $self->errString);
639     return($rs);
640 }
641
642 # -----------------------------------------------------------------------------
643 # Sort
644 #
645 # Sorting of multiple result sets is not supported by zebra...
646 # -----------------------------------------------------------------------------
647
648 sub sortResultsets {
649     my ($self, $sortspec, $setname, @sets) = @_;
650
651     $self->checkzh;
652
653     if ($#sets > 0) {
654         croak ("Sorting/merging of multiple resultsets is not supported now");
655     }
656
657     my @setnames;
658     my $count = 0;
659     foreach my $rs (@sets) {
660         push (@setnames, $rs->{name});
661         $count += $rs->{recordCount};  # is this really sure ??? It doesn't 
662                                        # matter now...
663     }
664
665     my $status = IDZebra::sort($self->{zh},
666                                $self->{odr_output},
667                                $sortspec,
668                                $setname,
669                                \@setnames);
670
671     my $errCode = $self->errCode;
672     my $errString = $self->errString;
673
674     logf (LOG_LOG, "Sort status $setname: %d, errCode: %d, errString: %s", 
675           $status, $errCode, $errString);
676
677     if ($status || $errCode) {$count = 0;}
678
679     my $rs  = IDZebra::Resultset->new($self,
680                                       name        => $setname,
681                                       recordCount => $count,
682                                       errCode     => $errCode,
683                                       errString   => $errString);
684     
685     return ($rs);
686 }
687 # -----------------------------------------------------------------------------
688 # Scan
689 # -----------------------------------------------------------------------------
690 sub scan {
691     my ($self, %args) = @_;
692
693     $self->checkzh;
694
695     unless ($args{expression}) {
696         croak ("No scan expression given");
697     }
698
699     my $sl = IDZebra::ScanList->new($self,%args);
700
701     return ($sl);
702 }
703
704 # ============================================================================
705
706 __END__
707
708 =head1 NAME
709
710 IDZebra::Session - A Zebra database server session for update and retrieval
711
712 =head1 SYNOPSIS
713
714   $sess = IDZebra::Session->new(configFile => 'demo/zebra.cfg');
715   $sess->open();
716
717   $sess = IDZebra::Session->open(configFile => 'demo/zebra.cfg',
718                                  groupName  => 'demo1');
719
720   $sess->group(groupName => 'demo2');
721
722   $sess->init();
723
724   $sess->begin_trans;
725
726   $sess->update(path      =>  'lib');
727
728   my $s1=$sess->update_record(data       => $rec1,
729                               recordType => 'grs.perl.pod',
730                               groupName  => "demo1",
731                               );
732
733   my $stat = $sess->end_trans;
734
735   $sess->databases('demo1','demo2');
736
737   my $rs1 = $sess->search(cqlmap    => 'demo/cql.map',
738                           cql       => 'dc.title=IDZebra',
739                           databases => [qw(demo1 demo2)]);
740   $sess->close;
741
742 =head1 DESCRIPTION
743
744 Zebra is a high-performance, general-purpose structured text indexing and retrieval engine. It reads structured records in a variety of input formats (eg. email, XML, MARC) and allows access to them through exact boolean search expressions and relevance-ranked free-text queries. 
745
746 Zebra supports large databases (more than ten gigabytes of data, tens of millions of records). It supports incremental, safe database updates on live systems. You can access data stored in Zebra using a variety of Index Data tools (eg. YAZ and PHP/YAZ) as well as commercial and freeware Z39.50 clients and toolkits. 
747
748 =head1 OPENING AND CLOSING A ZEBRA SESSIONS
749
750 For the time beeing only local database services are supported, the same way as calling zebraidx or zebrasrv from the command shell. In order to open a local Zebra database, with a specific configuration file, use
751
752   $sess = IDZebra::Session->new(configFile => 'demo/zebra.cfg');
753   $sess->open();
754
755 or
756
757   $sess = IDZebra::Session->open(configFile => 'demo/zebra.cfg');
758
759 where $sess is going to be the object representing a Zebra Session. Whenever this variable gets out of scope, the session is closed, together with all active transactions, etc... Anyway, if you'd like to close the session, just say:
760
761   $sess->close();
762
763 This will
764   - close all transactions
765   - destroy all result sets and scan lists 
766   - close the session
767
768 Note, that if I<shadow registers> are enabled, the changes will not be committed automatically.
769
770 In the future different database access methods are going to be available, 
771 like:
772
773   $sess = IDZebra::Session->open(server => 'ostrich.technomat.hu:9999');
774
775 You can also use the B<record group> arguments described below directly when calling the constructor, or the open method:
776
777   $sess = IDZebra::Session->open(configFile => 'demo/zebra.cfg',
778                                  groupName  => 'demo');
779
780
781 =head1 RECORD GROUPS 
782
783 If you manage different sets of records that share common characteristics, you can organize the configuration settings for each type into "groups". See the Zebra manual on the configuration file (zebra.cfg). 
784
785 For each open session a default record group is assigned. You can configure it in the constructor, or by the B<group> method:
786
787   $sess->group(groupName => ..., ...)
788
789 The following options are available:
790
791 =over 4
792
793 =item B<groupName>
794
795 This will select the named record group, and load the corresponding settings from the configuration file. All subsequent values will overwrite those...
796
797 =item B<databaseName>
798
799 The name of the (logical) database the updated records will belong to. 
800
801 =item B<path>
802
803 This path is used for directory updates (B<update>, B<delete> methods);
804  
805 =item B<recordId>
806
807 This option determines how to identify your records. See I<Zebra manual: Locating Records>
808
809 =item B<recordType>
810
811 The record type used for indexing. 
812
813 =item B<flagStoreData> 
814
815 Specifies whether the records should be stored internally in the Zebra system files. If you want to maintain the raw records yourself, this option should be false (0). If you want Zebra to take care of the records for you, it should be true(1). 
816
817 =item B<flagStoreKeys>
818
819 Specifies whether key information should be saved for a given group of records. If you plan to update/delete this type of records later this should be specified as 1; otherwise it should be 0 (default), to save register space. 
820
821 =item B<flagRw>
822
823 ?
824
825 =item B<fileVerboseLimit>
826
827 Skip log messages, when doing a directory update, and the specified number of files are processed...
828
829 =item B<databaseNamePath>
830
831 ?
832
833 =item B<explainDatabase>
834
835 The name of the explain database to be used
836
837 =item B<followLinks>              
838
839 Follow links when doing directory update.
840
841 =back
842
843 You can use the same parameters calling all update methods.
844
845 =head1 TRANSACTIONS (READ / WRITE LOCKS)
846
847 A transaction is a block of record update (insert / modify / delete) or retrieval procedures. So, all call to such function will implicitly start a transaction, unless one is already started by
848
849   $sess->begin_trans;
850
851 or 
852
853   $sess->begin_trans(TRANS_RW)
854
855 (these two are equivalents). The effect of this call is a kind of lock: if you call is a write lock is put on the registers, so other processes trying to update the database will be blocked. If there is already an RW (Read-Write) transaction opened by another process, the I<begin_trans> call will be blocked.
856
857 You can also use
858
859   $sess->begin_trans(TRANS_RO),
860
861 if you would like to put on a "read lock". This one is B<deprecated>, as while you have explicitly opened a transaction for read, you can't open another one for update. For example:
862
863   $sess->begin_trans(TRANS_RO);
864   $sess->begin_tran(TRANS_RW); # invalid, die here
865   $sess->end_trans;
866   $sess->end_trans;
867
868 is invalid, but
869
870   $sess->begin_tran(TRANS_RW); 
871   $sess->begin_trans(TRANS_RO);
872   $sess->end_trans;
873   $sess->end_trans;
874
875 is valid, but probably useless. Note again, that for each retrieval call, an RO transaction is opened. I<TRANS_RW> and I<TRANS_RO> are exported by default by IDZebra::Session.pm.
876
877 For multiple per-record I<updates> it's efficient to start transactions explicitly: otherwise registers (system files, vocabularies, etc..) are updated one by one. After finishing all requested updates, use
878
879   $stat = $sess->end_trans;
880
881 The return value is a ZebraTransactionStatus object, containing the following members as a hash reference:
882
883   $stat->{processed} # Number of records processed
884   $stat->{updated}   # Number of records processed
885   $stat->{deleted}   # Number of records processed
886   $stat->{inserted}  # Number of records processed
887   $stat->{stime}     # System time used
888   $stat->{utime}     # User time used
889
890 Normally, if the perl code dies due to some runtime error, or the session is closed, then the API attempts to close all pending transactions.
891
892 =head1 THE SHADOW REGISTERS
893
894 The Zebra server supports updating of the index structures. That is, you can add, modify, or remove records from databases managed by Zebra without rebuilding the entire index. Since this process involves modifying structured files with various references between blocks of data in the files, the update process is inherently sensitive to system crashes, or to process interruptions: Anything but a successfully completed update process will leave the register files in an unknown state, and you will essentially have no recourse but to re-index everything, or to restore the register files from a backup medium. Further, while the update process is active, users cannot be allowed to access the system, as the contents of the register files may change unpredictably. 
895
896 You can solve these problems by enabling the shadow register system in Zebra. During the updating procedure, zebraidx will temporarily write changes to the involved files in a set of "shadow files", without modifying the files that are accessed by the active server processes. If the update procedure is interrupted by a system crash or a signal, you simply repeat the procedure - the register files have not been changed or damaged, and the partially written shadow files are automatically deleted before the new updating procedure commences. 
897
898 At the end of the updating procedure (or in a separate operation, if you so desire), the system enters a "commit mode". First, any active server processes are forced to access those blocks that have been changed from the shadow files rather than from the main register files; the unmodified blocks are still accessed at their normal location (the shadow files are not a complete copy of the register files - they only contain those parts that have actually been modified). If the commit process is interrupted at any point during the commit process, the server processes will continue to access the shadow files until you can repeat the commit procedure and complete the writing of data to the main register files. You can perform multiple update operations to the registers before you commit the changes to the system files, or you can execute the commit operation at the end of each update operation. When the commit phase has completed successfully, any running server processes are instructed to switch their operations to the new, operational register, and the temporary shadow files are deleted. 
899
900 By default, (in the API !) the use of shadow registers is disabled. If zebra is configured that way (there is a "shadow" entry in zebra.cfg), then the shadow system can be enabled by calling:
901
902  $sess->shadow(1);
903
904 or disabled by
905
906  $sess->shadow(0);
907
908 If shadow system is enabled, then you have to commit changes you did, by calling:
909  
910  $sess->commit;
911
912 Note, that you can also determine shadow usage in the session constructor:
913
914  $sess = IDZebra::Session->open(configFile => 'demo/zebra.cfg',
915                                 shadow    => 1);
916  
917 Changes to I<shadow> will not have effect, within a I<transaction> (ie.: a transaction is started either with shadow enabled or disabled). For more details, read Zebra documentation: I<Safe Updating - Using Shadow Registers>.
918
919 =head1 UPDATING DATA
920
921 There are two ways to update data in a Zebra database using the perl API. You can update an entire directory structure just the way it's done by zebraidx:
922
923   $sess->update(path      =>  'lib');
924
925 This will update the database with the files in directory "lib", according to the current record group settings.
926
927   $sess->update();
928
929 This will update the database with the files, specified by the default record group setting. I<path> has to be specified there...
930
931   $sess->update(groupName => 'demo1',
932                 path      =>  'lib');
933
934 Update the database with files in "lib" according to the settings of group "demo1"
935
936   $sess->delete(groupName => 'demo1',
937                 path      =>  'lib');
938
939 Delete the records derived from the files in directory "lib", according to the "demo1" group settings. Sounds complex? Read zebra documentation about identifying records.
940
941 You can also update records one by one, even directly from the memory:
942
943   $sysno = $sess->update_record(data       => $rec1,
944                                 recordType => 'grs.perl.pod',
945                                 groupName  => "demo1");
946
947 This will update the database with the given record buffer. Note, that in this case recordType is explicitly specified, as there is no filename given, and for the demo1 group, no default record type is specified. The return value is the system assigned id of the record.
948
949 You can also index a single file:
950
951   $sysno = $sess->update_record(file => "lib/IDZebra/Data1.pm");
952
953 Or, provide a buffer, and a filename (where filename will only be used to identify the record, if configured that way, and possibly to find out it's record type):
954
955   $sysno = $sess->update_record(data => $rec1,
956                                 file => "lib/IDZebra/Data1.pm");
957
958 And some crazy stuff:
959
960   $sysno = $sess->delete_record(sysno => $sysno);
961
962 where sysno in itself is sufficient to identify the record
963
964   $sysno = $sess->delete_record(data => $rec1,
965                                 recordType => 'grs.perl.pod',
966                                 groupName  => "demo1");
967
968 This case the record is extracted, and if already exists, located in the database, then deleted... 
969
970   $sysno = $sess->update_record(data       => $rec1,
971                                 match      => $myid,
972                                 recordType => 'grs.perl.pod',
973                                 groupName  => "demo1");
974
975 Don't try this at home! This case, the record identifier string (which is normally generated according to the rules set in I<recordId> member of the record group, or in the I<recordId> parameter) is provided directly.... Looks much better this way:
976
977   $sysno = $sess->update_record(data          => $rec1,
978                                 databaseName  => 'books',
979                                 recordId      => '(bib1,ISBN)',
980                                 recordType    => 'grs.perl.pod',
981                                 flagStoreData => 1,
982                                 flagStoreKeys => 1);
983
984 You can notice, that it's not necessary to define a record group in zebra.cfg: you can do it "on the fly" in your code.
985
986 B<Important:> Note, that one record can be updated only once within a transaction - all subsequent updates are skipped. If you'd like to override this feature, use the I<force=E<gt>1> flag:
987
988   $sysno = $sess->update_record(data       => $rec1,
989                                 recordType => 'grs.perl.pod',
990                                 groupName  => "demo1",
991                                 force      => 1);
992
993 If you don't like to update the record, if it alerady exists, use the I<insert_record> method:
994
995   $sysno = $sess->insert_record(data       => $rec1,
996                                 recordType => 'grs.perl.pod',
997                                 groupName  => "demo1");
998
999 In this case, sysno will be -1, if the record could not be added, because there was already one in the database, with the same record identifier (generated according to the I<recordId> setting).
1000
1001 =head1 DATABASE SELECTION
1002
1003 Within a zebra repository you can define logical databases. You can either do this by record groups, or by providing the databaseName argument for update methods. For each record the database name it belongs to is stored. 
1004
1005 For searching, you can select databases by calling:
1006
1007   $sess->databases('db1','db2');
1008
1009 This will not do anything if the given and only the given databases are already selected. You can get the list of the actually selected databases, by calling:
1010   
1011   @dblist = $sess->databases();
1012
1013 =head1 SEARCHING
1014
1015 It's nice to be able to store data in your repository... But it's useful to reach it as well. So this is how to do searching:
1016
1017   $rs = $sess->search(databases => [qw(demo1,demo2)], # optional
1018                       pqf       => '@attr 1=4 computer');
1019
1020 This is going to execute a search in databases demo1 and demo2, for title 'com,puter'. This is a PQF (Prefix Query Format) search, see YAZ documentation for details. The database selection is optional: if it's provided, the given list of databases is selected for this particular search, then the original selection is restored.
1021
1022 =head2 CCL searching
1023
1024 Not all users enjoy typing in prefix query structures and numerical attribute values, even in a minimalistic test client. In the library world, the more intuitive Common Command Language (or ISO 8777) has enjoyed some popularity - especially before the widespread availability of graphical interfaces. It is still useful in applications where you for some reason or other need to provide a symbolic language for expressing boolean query structures. 
1025
1026 The CCL searching is not currently supported by this API.
1027
1028 =head2 CQL searching
1029
1030 CQL - Common Query Language - was defined for the SRW protocol. In many ways CQL has a similar syntax to CCL. The objective of CQL is different. Where CCL aims to be an end-user language, CQL is the protocol query language for SRW. 
1031
1032 In order to map CQL queries to Zebra internal search structures, you have to define a mapping, the way it is described in YAZ documentation: I<Specification of CQL to RPN mapping>. The mapping is interpreted by the method:
1033
1034   $sess->cqlmap($mapfile);
1035
1036 Or, you can directly provide the I<mapfile> parameter for the search:
1037
1038   $rs = $sess->search(cqlmap    => 'demo/cql.map',
1039                       cql       => 'dc.title=IDZebra');
1040
1041 As you see, CQL searching is so simple: just give the query in the I<cql> parameter.
1042
1043 =head2 Sorting
1044
1045 If you'd like the search results to be sorted, use the I<sort> parameter:
1046
1047   $rs = $sess->search(cql       => 'IDZebra',
1048                       sort      => '1=4 ia');
1049   
1050 Note, that B<currently> this is (almost) equivalent to
1051
1052   $rs = $sess->search(cql       => 'IDZebra');
1053   $rs->sort('1=4 ia');
1054   
1055 but in the further versions of Zebra and this API a single phase search and sort will take place, optimizing performance. For more details on sorting, see I<IDZebra::ResultSet> manpage.
1056
1057 =head1 RESULTSETS
1058
1059 As you have seen, the result of the search request is a I<Resultset> object.
1060 It contains number of hits, and search status, and can be used to sort and retrieve the resulting records.
1061
1062   $count = $rs->count;
1063
1064   printf ("RS Status is %d (%s)\n", $rs->errCode, $rs->errString);
1065
1066 I<$rs-E<gt>errCode> is 0, if there were no errors during search. Read the I<IDZebra::Resultset> manpage for more details.
1067
1068 =head1 SCANNING
1069
1070 Zebra supports scanning index values. The result of the 
1071
1072   $sl = $sess->scan(expression => "a");
1073
1074 call is an I<IDZebra::ScanList> object, what you can use to list the values. The scan expression has to be provided in a PQF like format. Examples:
1075
1076 B< a> (scan trough words of "default", "Any" indexes)
1077
1078
1079 B< @attr 1=1016 a> (same effect)
1080
1081
1082 B< @attr 1=4 @attr 6=2 a>  (scan trough titles as phrases)
1083
1084 An illegal scan expression will cause your code to die. If you'd like to select databases just for the scan call, you can optionally use the I<databases> parameter:
1085
1086   $sl = $sess->scan(expression => "a",
1087                     databases  => [qw(demo1 demo2)]);
1088   
1089 You can use the I<IDZebra::ScanList> object returned by the i<scan> method, to reach the result. Check I<IDZebra::ScanList> manpage for more details.
1090
1091 =head1 SESSION STATUS AND ERRORS
1092
1093 Most of the API calls causes die, if an error occures. You avoid this, by using eval {} blocks. The following methods are available to get the status of Zebra service:
1094
1095 =over 4
1096
1097 =item B<errCode>
1098
1099 The Zebra provided error code... (for the result of the last call);
1100
1101 =item B<errString>
1102
1103 Error string corresponding to the message
1104
1105 =item B<errAdd>
1106
1107 Additional information for the status
1108
1109 =back
1110
1111 This functionality may change, see TODO.
1112
1113 =head1 LOGGING AND MISC. FUNCTIONS
1114
1115 Zebra provides logging facility for the internal events, and also for application developers trough the API. See manpage I<IDZebra::Logger> for details.
1116
1117 =over 4
1118
1119 =item B<IDZebra::LogFile($filename)>
1120
1121 Will set the output file for logging. By default it's STDERR;
1122
1123 =item B<IDZebra::LogLevel(15)>
1124
1125 Set log level. 0 for no logs. See IDZebra::Logger for usable flags.
1126
1127 =back
1128
1129 Some other functions
1130
1131 =over 4
1132
1133 =item B<$sess-E<gt>init>
1134
1135 Initialize, and clean registers. This will remove all data!
1136
1137 =item B<$sess-E<gt>compact>
1138
1139 Compact the registers (? does this work)
1140
1141 =item B<$sess-E<gt>show>
1142
1143 Doesn't have too much meaning. Don't try :)
1144
1145 =back
1146
1147 =head1 TODO
1148
1149 =over 4
1150
1151 =item B<Clean up error handling>
1152
1153 By default all zebra errors should cause die. (such situations could be avoided by using eval {}), and then check for errCode, errString... An optional flag or package variable should be introduced to override this, and skip zebra errors, to let the user decide what to do.
1154
1155 =item B<Make the package self-distributable>
1156
1157 Build and link with installed header and library files
1158
1159 =item B<Testing>
1160
1161 Test shadow system, unicode...
1162
1163 =item B<C API>
1164
1165 Cleanup, arrange, remove redundancy
1166
1167 =back
1168
1169 =head1 COPYRIGHT
1170
1171 Fill in
1172
1173 =head1 AUTHOR
1174
1175 Peter Popovics, pop@technomat.hu
1176
1177 =head1 SEE ALSO
1178
1179 Zebra documentation, Zebra::ResultSet, Zebra::ScanList, Zebra::Logger manpages
1180
1181 =cut