]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg.pm
adding full marc21 record support
[working/Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Storage / Driver / Pg.pm
1 { # Based on the change to Class::DBI in OpenILS::Application::Storage.  This will
2   # allow us to use TSearch2 via a simple cdbi "search" interface.
3         #-------------------------------------------------------------------------------
4         use Class::DBI;
5         package Class::DBI;
6
7         sub search_fti {
8                 my $self = shift;
9                 my @args = @_;
10                 if (ref($args[-1]) eq 'HASH') {
11                         $args[-1]->{_placeholder} = "to_tsquery('default',?)";
12                 } else {
13                         push @args, {_placeholder => "to_tsquery('default',?)"};
14                 }
15                 $self->_do_search("@@"  => @args);
16         }
17 }
18
19 { # Every driver needs to provide a 'compile()' method to OpenILS::Application::Storage::FTS.
20   # If that driver wants to support FTI, that is...
21         #-------------------------------------------------------------------------------
22         package OpenILS::Application::Storage::FTS;
23         use OpenSRF::Utils::Logger qw/:level/;
24         my $log = 'OpenSRF::Utils::Logger';
25
26         sub compile {
27                 my $self = shift;
28                 my $term = shift;
29
30                 $self = ref($self) || $self;
31                 $self = bless {} => $self;
32
33                 $self->decompose($term);
34
35                 my $newterm = join('&', $self->words);
36
37                 if ($self->nots) {
38                         $newterm = '('.$newterm.')&('. join('|', $self->nots) . ')';
39                 }
40
41                 $newterm = OpenILS::Application::Storage->driver->quote($newterm);
42
43                 $self->{fts_query} = ["to_tsquery('default',$newterm)"];
44                 $self->{fts_query_nots} = [];
45                 $self->{fts_op} = '@@';
46
47                 return $self;
48         }
49 }
50
51
52 { # The driver package itself just needs a db_Main method (or db_Slaves if
53   #Class::DBI::Replication is in use) for Class::DBI to call.
54   #
55   # Any other fixups can go in here too... Also, the drivers should subclass the
56   # DBI driver that they are wrapping, or provide a 'quote()' method that calls
57   # the DBD::xxx::quote() method on FTI's behalf.
58   #
59   # The dirver MUST be a subclass of Class::DBI(::Replication) and
60   # OpenILS::Application::Storage.
61   #-------------------------------------------------------------------------------
62         package OpenILS::Application::Storage::Driver::Pg;
63         use Class::DBI;
64         use base qw/Class::DBI OpenILS::Application::Storage/;
65         use DBI;
66         use OpenSRF::EX qw/:try/;
67         use OpenSRF::DomainObject::oilsResponse;
68         use OpenSRF::Utils::Logger qw/:level/;
69         my $log = 'OpenSRF::Utils::Logger';
70
71         __PACKAGE__->set_sql( retrieve_limited => 'SELECT * FROM __TABLE__ ORDER BY id LIMIT ?' );
72
73         my $master_db;
74         my @slave_dbs;
75         my $_db_params;
76         sub child_init {
77                 my $self = shift;
78                 $_db_params = shift;
79
80                 $log->debug("Running child_init inside ".__PACKAGE__, INTERNAL);
81
82                 $_db_params = [ $_db_params ] unless (ref($_db_params) eq 'ARRAY');
83
84                 my %attrs = (   %{$self->_default_attributes},
85                                 RootClass => 'DBIx::ContextualFetch',
86                                 ShowErrorStatement => 1,
87                                 RaiseError => 1,
88                                 AutoCommit => 1,
89                                 PrintError => 1,
90                                 Taint => 1,
91                                 pg_enable_utf8 => 1,
92                                 FetchHashKeyName => 'NAME_lc',
93                                 ChopBlanks => 1,
94                 );
95
96                 my $master = shift @$_db_params;
97                 $master_db = DBI->connect("dbi:Pg:host=$$master{host};dbname=$$master{db}",$$master{user},$$master{pw}, \%attrs);
98                 $master_db->do("SET NAMES '$$master{client_encoding}';") if ($$master{client_encoding});
99
100                 $log->debug("Connected to MASTER db '$$master{db} at $$master{host}", INFO);
101                 
102                 for my $db (@$_db_params) {
103                         push @slave_dbs, DBI->connect("dbi:Pg:host=$$db{host};dbname=$$db{db}",$$db{user},$$db{pw}, \%attrs);
104                         $slave_dbs[-1]->do("SET NAMES '$$db{client_encoding}';") if ($$master{client_encoding});
105
106                         $log->debug("Connected to MASTER db '$$master{db} at $$master{host}", INFO);
107                 }
108
109                 $log->debug("All is well on the western front", INTERNAL);
110         }
111
112         sub db_Main {
113                 my $self = shift;
114                 return $master_db if ($self->current_xact_session);
115                 return $master_db unless (@slave_dbs);
116                 return ($master_db, @slave_dbs)[rand(scalar(@slave_dbs))];
117         }
118
119         sub quote {
120                 return __PACKAGE__->db_Main->quote(@_)
121         }
122
123 #       sub tsearch2_trigger {
124 #               my $self = shift;
125 #               return unless ($self->value);
126 #               $self->index_vector(
127 #                       $self->db_Slaves->selectrow_array(
128 #                               "SELECT to_tsvector('default',?);",
129 #                               {},
130 #                               $self->value
131 #                       )
132 #               );
133 #       }
134
135         my $_xact_session;
136
137         sub current_xact_session {
138                 my $self = shift;
139                 if (defined($_xact_session)) {
140                         return $_xact_session;
141                 }
142                 return undef;
143         }
144
145         sub current_xact_is_auto {
146                 my $self = shift;
147                 return $_xact_session->session_data(autocommit => shift());
148         }
149
150         sub current_xact_id {
151                 my $self = shift;
152                 if (defined($_xact_session) and ref($_xact_session)) {
153                         return $_xact_session->session_id;
154                 }
155                 return undef;
156         }
157
158         sub set_xact_session {
159                 my $self = shift;
160                 my $ses = shift;
161                 if (!defined($ses)) {
162                         return undef;
163                 }
164                 $_xact_session = $ses;
165                 return $_xact_session;
166         }
167
168         sub unset_xact_session {
169                 my $self = shift;
170                 my $ses = $_xact_session;
171                 undef $_xact_session;
172                 return $ses;
173         }
174
175 }
176
177
178 {
179         package OpenILS::Application::Storage;
180         use OpenSRF::Utils::Logger;
181         my $log = 'OpenSRF::Utils::Logger';
182
183         my $pg = 'OpenILS::Application::Storage::Driver::Pg';
184
185         sub pg_begin_xaction {
186                 my $self = shift;
187                 my $client = shift;
188
189                 if (my $old_xact = $pg->current_xact_session) {
190                         if ($pg->current_xact_is_auto) {
191                                 $log->debug("Commiting old autocommit transaction with Open-ILS XACT-ID [$old_xact]", INFO);
192                                 $self->pg_commit_xaction($client);
193                         } else {
194                                 $log->debug("Rolling back old NON-autocommit transaction with Open-ILS XACT-ID [$old_xact]", INFO);
195                                 $self->pg_rollback_xaction($client);
196                                 return new OpenSRF::DomainObject::oilsException (
197                                                 statusCode => 500,
198                                                 status => "Previous transaction rolled back!",
199                                 );
200                         }
201                 }
202                 
203                 $pg->set_xact_session( $client->session );
204                 my $xact_id = $pg->current_xact_id;
205
206                 $log->debug("Beginning a new trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
207
208                 my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
209                 
210                 try {
211                         $dbh->begin_work;
212
213                 } catch Error with {
214                         my $e = shift;
215                         $log->debug("Failed to begin a new trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
216                         return $e;
217                 };
218
219
220                 my $death_cb = $client->session->register_callback(
221                         death => sub {
222                                 __PACKAGE__->pg_rollback_xaction;
223                         }
224                 );
225
226                 $log->debug("Registered 'death' callback [$death_cb] for new trasaction with Open-ILS XACT-ID [$xact_id]", DEBUG);
227
228                 $client->session->session_data( death_cb => $death_cb );
229
230                 if ($self->api_name =~ /autocommit$/o) {
231                         $pg->current_xact_is_auto(1);
232                         my $dc_cb = $client->session->register_callback(
233                                 disconnect => sub {
234                                         my $ses = shift;
235                                         $ses->unregister_callback($death_cb);
236                                         __PACKAGE__->pg_commit_xaction;
237                                 }
238                         );
239                         $log->debug("Registered 'disconnect' callback [$dc_cb] for new trasaction with Open-ILS XACT-ID [$xact_id]", DEBUG);
240                         if ($client and $client->session) {
241                                 $client->session->session_data( disconnect_cb => $dc_cb );
242                         }
243                 }
244
245                 return 1;
246
247         }
248         __PACKAGE__->register_method(
249                 method          => 'pg_begin_xaction',
250                 api_name        => 'open-ils.storage.transaction.begin',
251                 api_level       => 1,
252                 argc            => 0,
253         );
254         __PACKAGE__->register_method(
255                 method          => 'pg_begin_xaction',
256                 api_name        => 'open-ils.storage.transaction.begin.autocommit',
257                 api_level       => 1,
258                 argc            => 0,
259         );
260
261         sub pg_commit_xaction {
262                 my $self = shift;
263
264
265                 try {
266                         $log->debug("Committing trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
267                         my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
268                         $dbh->commit;
269
270                 } catch Error with {
271                         my $e = shift;
272                         $log->debug("Failed to commit trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
273                         return 0;
274                 };
275                 
276                 $pg->current_xact_session->unregister_callback(
277                         $pg->current_xact_session->session_data( 'death_cb' )
278                 );
279
280                 if ($pg->current_xact_is_auto) {
281                         $pg->current_xact_session->unregister_callback(
282                                 $pg->current_xact_session->session_data( 'disconnect_cb' )
283                         );
284                 }
285
286                 $pg->unset_xact_session;
287
288                 return 1;
289                 
290         }
291         __PACKAGE__->register_method(
292                 method          => 'pg_commit_xaction',
293                 api_name        => 'open-ils.storage.transaction.commit',
294                 api_level       => 1,
295                 argc            => 0,
296         );
297
298         sub pg_rollback_xaction {
299                 my $self = shift;
300
301                 my $xact_id = $pg->current_xact_id;
302                 try {
303                         my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
304                         $log->debug("Rolling back a trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
305                         $dbh->rollback;
306
307                 } catch Error with {
308                         my $e = shift;
309                         $log->debug("Failed to roll back trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
310                         return 0;
311                 };
312         
313                 $pg->current_xact_session->unregister_callback(
314                         $pg->current_xact_session->session_data( 'death_cb' )
315                 );
316
317                 if ($pg->current_xact_is_auto) {
318                         $pg->current_xact_session->unregister_callback(
319                                 $pg->current_xact_session->session_data( 'disconnect_cb' )
320                         );
321                 }
322
323                 $pg->unset_xact_session;
324
325                 return 1;
326         }
327         __PACKAGE__->register_method(
328                 method          => 'pg_rollback_xaction',
329                 api_name        => 'open-ils.storage.transaction.rollback',
330                 api_level       => 1,
331                 argc            => 0,
332         );
333
334 }
335
336 {
337         #---------------------------------------------------------------------
338         package asset::call_number;
339         
340         asset::call_number->table( 'asset.call_number' );
341         asset::call_number->sequence( 'asset.call_number_id_seq' );
342         
343         #---------------------------------------------------------------------
344         package asset::copy;
345         
346         asset::copy->table( 'asset.copy' );
347         asset::copy->sequence( 'asset.copy_id_seq' );
348         
349         #---------------------------------------------------------------------
350         package biblio::record_entry;
351         
352         biblio::record_entry->table( 'biblio.record_entry' );
353         biblio::record_entry->sequence( 'biblio.record_entry_id_seq' );
354
355         #---------------------------------------------------------------------
356         package biblio::record_node;
357         
358         biblio::record_node->table( 'biblio.record_data' );
359         biblio::record_node->sequence( 'biblio.record_data_id_seq' );
360         
361         #---------------------------------------------------------------------
362         package biblio::record_marc;
363         
364         biblio::record_marc->table( 'biblio.record_marc' );
365         biblio::record_marc->sequence( 'biblio.record_marc_id_seq' );
366
367         #---------------------------------------------------------------------
368         package biblio::record_mods;
369         
370         biblio::record_mods->table( 'biblio.record_mods' );
371         biblio::record_mods->sequence( 'biblio.record_mods_id_seq' );
372
373         #---------------------------------------------------------------------
374         package biblio::record_note;
375         
376         biblio::record_note->table( 'biblio.record_note' );
377         biblio::record_note->sequence( 'biblio.record_note_id_seq' );
378         
379         #---------------------------------------------------------------------
380         package actor::user;
381         
382         actor::user->table( 'actor.usr' );
383         actor::user->sequence( 'actor.usr_id_seq' );
384         
385         #---------------------------------------------------------------------
386         package actor::org_unit_type;
387         
388         actor::org_unit_type->table( 'actor.org_unit_type' );
389         actor::org_unit_type->sequence( 'actor.org_unit_type_id_seq' );
390
391         #---------------------------------------------------------------------
392         package actor::org_unit;
393         
394         actor::org_unit_type->table( 'actor.org_unit' );
395         actor::org_unit_type->sequence( 'actor.org_unit_id_seq' );
396
397         #---------------------------------------------------------------------
398
399         #-------------------------------------------------------------------------------
400         package metabib::metarecord;
401
402         metabib::metarecord->table( 'metabib.metarecord' );
403         metabib::metarecord->sequence( 'metabib.metarecord_id_seq' );
404
405         #-------------------------------------------------------------------------------
406
407         #-------------------------------------------------------------------------------
408         package metabib::title_field_entry;
409
410         metabib::title_field_entry->table( 'metabib.title_field_entry' );
411         metabib::title_field_entry->sequence( 'metabib.title_field_entry_id_seq' );
412
413 #       metabib::title_field_entry->add_trigger(
414 #               before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
415 #       );
416 #       metabib::title_field_entry->add_trigger(
417 #               before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
418 #       );
419
420         #-------------------------------------------------------------------------------
421
422         #-------------------------------------------------------------------------------
423         package metabib::author_field_entry;
424
425         metabib::author_field_entry->table( 'metabib.author_field_entry' );
426         metabib::author_field_entry->sequence( 'metabib.author_field_entry_id_seq' );
427
428         #-------------------------------------------------------------------------------
429
430         #-------------------------------------------------------------------------------
431         package metabib::subject_field_entry;
432
433         metabib::subject_field_entry->table( 'metabib.subject_field_entry' );
434         metabib::subject_field_entry->sequence( 'metabib.subject_field_entry_id_seq' );
435
436         #-------------------------------------------------------------------------------
437
438         #-------------------------------------------------------------------------------
439         package metabib::keyword_field_entry;
440
441         metabib::keyword_field_entry->table( 'metabib.keyword_field_entry' );
442         metabib::keyword_field_entry->sequence( 'metabib.keyword_field_entry_id_seq' );
443
444         #-------------------------------------------------------------------------------
445
446         #-------------------------------------------------------------------------------
447         package metabib::title_field_entry_source_map;
448
449         metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map' );
450
451         #-------------------------------------------------------------------------------
452
453         #-------------------------------------------------------------------------------
454         package metabib::author_field_entry_source_map;
455
456         metabib::author_field_entry_source_map->table( 'metabib.author_field_entry_source_map' );
457
458         #-------------------------------------------------------------------------------
459
460         #-------------------------------------------------------------------------------
461         package metabib::subject_field_entry_source_map;
462
463         metabib::subject_field_entry_source_map->table( 'metabib.subject_field_entry_source_map' );
464
465         #-------------------------------------------------------------------------------
466
467         #-------------------------------------------------------------------------------
468         package metabib::keyword_field_entry_source_map;
469
470         metabib::keyword_field_entry_source_map->table( 'metabib.keyword_field_entry_source_map' );
471
472         #-------------------------------------------------------------------------------
473
474         #-------------------------------------------------------------------------------
475         package metabib::metarecord_source_map;
476
477         metabib::metarecord_source_map->table( 'metabib.full_rec' );
478
479         #-------------------------------------------------------------------------------
480
481         #-------------------------------------------------------------------------------
482         package metabib::full_rec;
483
484         metabib::full_rec->table( 'metabib.full_rec' );
485         metabib::full_rec->sequence( 'metabib.full_rec_id_seq' );
486
487         #-------------------------------------------------------------------------------
488 }
489
490 1;