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 #-------------------------------------------------------------------------------
10 if (ref($args[-1]) eq 'HASH') {
11 $args[-1]->{_placeholder} = "to_tsquery('default',?)";
13 push @args, {_placeholder => "to_tsquery('default',?)"};
15 $self->_do_search("@@" => @args);
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';
30 $self = ref($self) || $self;
31 $self = bless {} => $self;
33 $self->decompose($term);
35 my $newterm = join('&', $self->words);
38 $newterm = '('.$newterm.')&('. join('|', $self->nots) . ')';
41 $newterm = OpenILS::Application::Storage->driver->quote($newterm);
43 $self->{fts_query} = ["to_tsquery('default',$newterm)"];
44 $self->{fts_query_nots} = [];
45 $self->{fts_op} = '@@';
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.
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.
59 # The dirver MUST be a subclass of Class::DBI(::Replication) and
60 # OpenILS::Application::Storage.
61 #-------------------------------------------------------------------------------
62 package OpenILS::Application::Storage::Driver::Pg;
64 use base qw/Class::DBI OpenILS::Application::Storage/;
66 use OpenSRF::EX qw/:try/;
67 use OpenSRF::DomainObject::oilsResponse;
68 use OpenSRF::Utils::Logger qw/:level/;
69 my $log = 'OpenSRF::Utils::Logger';
71 __PACKAGE__->set_sql( retrieve_limited => 'SELECT * FROM __TABLE__ ORDER BY id LIMIT ?' );
80 $log->debug("Running child_init inside ".__PACKAGE__, INTERNAL);
82 $_db_params = [ $_db_params ] unless (ref($_db_params) eq 'ARRAY');
84 my %attrs = ( %{$self->_default_attributes},
85 RootClass => 'DBIx::ContextualFetch',
86 ShowErrorStatement => 1,
92 FetchHashKeyName => 'NAME_lc',
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});
100 $log->debug("Connected to MASTER db at $$master{host}", INTERNAL);
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});
107 $log->debug("All is well on the western front", INTERNAL);
112 return $master_db if ($self->current_xact_session);
113 return $master_db unless (@slave_dbs);
114 return ($master_db, @slave_dbs)[rand(scalar(@slave_dbs))];
118 return __PACKAGE__->db_Main->quote(@_)
121 sub tsearch2_trigger {
123 return unless ($self->value);
125 $self->db_Slaves->selectrow_array(
126 "SELECT to_tsvector('default',?);",
135 sub current_xact_session {
137 if (defined($_xact_session)) {
138 return $_xact_session;
143 sub current_xact_is_auto {
145 return $_xact_session->session_data(autocommit => shift());
148 sub current_xact_id {
150 if (defined($_xact_session) and ref($_xact_session)) {
151 return $_xact_session->session_id;
156 sub set_xact_session {
159 if (!defined($ses)) {
162 $_xact_session = $ses;
163 return $_xact_session;
166 sub unset_xact_session {
168 my $ses = $_xact_session;
169 undef $_xact_session;
177 package OpenILS::Application::Storage;
178 use OpenSRF::Utils::Logger;
179 my $log = 'OpenSRF::Utils::Logger';
181 my $pg = 'OpenILS::Application::Storage::Driver::Pg';
183 sub pg_begin_xaction {
187 if (my $old_xact = $pg->current_xact_session) {
188 if ($pg->current_xact_is_auto) {
189 $log->debug("Commiting old autocommit transaction with Open-ILS XACT-ID [$old_xact]", INFO);
190 OpenILS::Application::Storage::CDBI->db_Main->commit;
192 $log->debug("Rolling back old NON-autocommit transaction with Open-ILS XACT-ID [$old_xact]", INFO);
193 __PACKAGE__->pg_rollback_xaction($client);
194 return new OpenSRF::DomainObject::oilsException (
196 status => "Previous transaction rolled back!",
201 $pg->set_xact_session( $client->session );
202 my $xact_id = $pg->current_xact_id;
204 $log->debug("Beginning a new trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
206 my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
213 $log->debug("Failed to begin a new trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
218 my $death_cb = $client->session->register_callback(
220 __PACKAGE__->pg_rollback_xaction;
224 $log->debug("Registered 'death' callback [$death_cb] for new trasaction with Open-ILS XACT-ID [$xact_id]", DEBUG);
226 $client->session->session_data( death_cb => $death_cb );
228 if ($self->api_name =~ /autocommit$/o) {
229 $pg->current_xact_is_auto(1);
230 my $dc_cb = $client->session->register_callback(
233 $ses->unregister_callback($death_cb);
234 __PACKAGE__->pg_commit_xaction;
237 $log->debug("Registered 'disconnect' callback [$dc_cb] for new trasaction with Open-ILS XACT-ID [$xact_id]", DEBUG);
238 $client->session->session_data( disconnect_cb => $dc_cb );
244 __PACKAGE__->register_method(
245 method => 'pg_begin_xaction',
246 api_name => 'open-ils.storage.transaction.begin',
250 __PACKAGE__->register_method(
251 method => 'pg_begin_xaction',
252 api_name => 'open-ils.storage.transaction.begin.autocommit',
257 sub pg_commit_xaction {
262 $log->debug("Committing trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
263 my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
268 $log->debug("Failed to commit trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
272 $pg->current_xact_session->unregister_callback(
273 $pg->current_xact_session->session_data( 'death_cb' )
276 if ($pg->current_xact_is_auto) {
277 $pg->current_xact_session->unregister_callback(
278 $pg->current_xact_session->session_data( 'disconnect_cb' )
282 $pg->unset_xact_session;
287 __PACKAGE__->register_method(
288 method => 'pg_commit_xaction',
289 api_name => 'open-ils.storage.transaction.commit',
294 sub pg_rollback_xaction {
297 my $xact_id = $pg->current_xact_id;
299 my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
300 $log->debug("Rolling back a trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
305 $log->debug("Failed to roll back trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
309 $pg->current_xact_session->unregister_callback(
310 $pg->current_xact_session->session_data( 'death_cb' )
313 if ($pg->current_xact_is_auto) {
314 $pg->current_xact_session->unregister_callback(
315 $pg->current_xact_session->session_data( 'disconnect_cb' )
319 $pg->unset_xact_session;
323 __PACKAGE__->register_method(
324 method => 'pg_rollback_xaction',
325 api_name => 'open-ils.storage.transaction.rollback',
333 #---------------------------------------------------------------------
334 package asset::call_number;
336 asset::call_number->table( 'asset.call_number' );
337 asset::call_number->sequence( 'asset.call_number_id_seq' );
339 #---------------------------------------------------------------------
342 asset::copy->table( 'asset.copy' );
343 asset::copy->sequence( 'asset.copy_id_seq' );
345 #---------------------------------------------------------------------
346 package biblio::record_entry;
348 biblio::record_entry->table( 'biblio.record_entry' );
349 biblio::record_entry->sequence( 'biblio.record_entry_id_seq' );
351 #---------------------------------------------------------------------
352 package biblio::record_node;
354 biblio::record_node->table( 'biblio.record_data' );
355 biblio::record_node->sequence( 'biblio.record_data_id_seq' );
357 #---------------------------------------------------------------------
358 package biblio::record_note;
360 biblio::record_note->table( 'biblio.record_note' );
361 biblio::record_note->sequence( 'biblio.record_note_id_seq' );
363 #---------------------------------------------------------------------
366 actor::user->table( 'actor.usr' );
367 actor::user->sequence( 'actor.usr_id_seq' );
369 #---------------------------------------------------------------------
370 package actor::org_unit_type;
372 actor::org_unit_type->table( 'actor.org_unit_type' );
373 actor::org_unit_type->sequence( 'actor.org_unit_type_id_seq' );
375 #---------------------------------------------------------------------
377 #-------------------------------------------------------------------------------
378 package metabib::metarecord;
380 metabib::metarecord->table( 'metabib.metarecord' );
381 metabib::metarecord->sequence( 'metabib.metarecord_id_seq' );
383 #-------------------------------------------------------------------------------
385 #-------------------------------------------------------------------------------
386 package metabib::title_field_entry;
388 metabib::title_field_entry->table( 'metabib.title_field_entry' );
389 metabib::title_field_entry->sequence( 'metabib.title_field_entry_id_seq' );
390 metabib::title_field_entry->columns( Primary => qw/id/ );
391 metabib::title_field_entry->columns( Essential => qw/id/ );
392 metabib::title_field_entry->columns( Others => qw/field value index_vector/ );
394 metabib::title_field_entry->add_trigger(
395 before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
397 metabib::title_field_entry->add_trigger(
398 before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
401 #-------------------------------------------------------------------------------
403 #-------------------------------------------------------------------------------
404 package metabib::author_field_entry;
406 metabib::author_field_entry->table( 'metabib.author_field_entry' );
407 metabib::author_field_entry->sequence( 'metabib.author_field_entry_id_seq' );
409 metabib::author_field_entry->add_trigger(
410 before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
412 metabib::author_field_entry->add_trigger(
413 before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
416 #-------------------------------------------------------------------------------
418 #-------------------------------------------------------------------------------
419 package metabib::subject_field_entry;
421 metabib::subject_field_entry->table( 'metabib.subject_field_entry' );
422 metabib::subject_field_entry->sequence( 'metabib.subject_field_entry_id_seq' );
424 metabib::subject_field_entry->add_trigger(
425 before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
427 metabib::subject_field_entry->add_trigger(
428 before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
431 #-------------------------------------------------------------------------------
433 #-------------------------------------------------------------------------------
434 package metabib::keyword_field_entry;
436 metabib::keyword_field_entry->table( 'metabib.keyword_field_entry' );
437 metabib::keyword_field_entry->sequence( 'metabib.keyword_field_entry_id_seq' );
439 metabib::keyword_field_entry->add_trigger(
440 before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
442 metabib::keyword_field_entry->add_trigger(
443 before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
446 #-------------------------------------------------------------------------------
448 #-------------------------------------------------------------------------------
449 package metabib::title_field_entry_source_map;
451 metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map' );
452 metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map_id_seq' );
454 #-------------------------------------------------------------------------------
456 #-------------------------------------------------------------------------------
457 package metabib::author_field_entry_source_map;
459 metabib::author_field_entry_source_map->table( 'metabib.author_field_entry_source_map' );
460 metabib::author_field_entry_source_map->sequence( 'metabib.author_field_entry_source_map_id_seq' );
462 #-------------------------------------------------------------------------------
464 #-------------------------------------------------------------------------------
465 package metabib::subject_field_entry_source_map;
467 metabib::subject_field_entry_source_map->table( 'metabib.subject_field_entry_source_map' );
468 metabib::subject_field_entry_source_map->sequence( 'metabib.subject_field_entry_source_map_id_seq' );
470 #-------------------------------------------------------------------------------