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 $log->debug("Compiled term is [$newterm]", DEBUG);
42 $newterm = OpenILS::Application::Storage::Driver::Pg->quote($newterm);
43 $log->debug("Quoted term is [$newterm]", DEBUG);
45 $self->{fts_query} = ["to_tsquery('default',$newterm)"];
46 $self->{fts_query_nots} = [];
47 $self->{fts_op} = '@@';
48 $self->{text_col} = shift;
49 $self->{fts_col} = shift;
54 sub sql_where_clause {
56 my $column = $self->fts_col;
60 for my $fts ( $self->fts_query ) {
61 push @output, join(' ', $self->fts_col, $self->{fts_op}, $fts);
62 push @ranks, "rank($column, $fts)";
64 $self->{fts_rank} = \@ranks;
66 my $phrase_match = $self->sql_exact_phrase_match();
67 return join(' AND ', @output) . $phrase_match;
73 { # The driver package itself just needs a db_Main method (or db_Slaves if
74 #Class::DBI::Replication is in use) for Class::DBI to call.
76 # Any other fixups can go in here too... Also, the drivers should subclass the
77 # DBI driver that they are wrapping, or provide a 'quote()' method that calls
78 # the DBD::xxx::quote() method on FTI's behalf.
80 # The dirver MUST be a subclass of Class::DBI(::Replication) and
81 # OpenILS::Application::Storage.
82 #-------------------------------------------------------------------------------
83 package OpenILS::Application::Storage::Driver::Pg;
85 use base qw/Class::DBI OpenILS::Application::Storage/;
87 use OpenSRF::EX qw/:try/;
88 use OpenSRF::DomainObject::oilsResponse;
89 use OpenSRF::Utils::Logger qw/:level/;
90 my $log = 'OpenSRF::Utils::Logger';
92 __PACKAGE__->set_sql( retrieve_limited => 'SELECT * FROM __TABLE__ ORDER BY id LIMIT ?' );
101 $log->debug("Running child_init inside ".__PACKAGE__, INTERNAL);
103 $_db_params = [ $_db_params ] unless (ref($_db_params) eq 'ARRAY');
105 my %attrs = ( %{$self->_default_attributes},
106 RootClass => 'DBIx::ContextualFetch',
107 ShowErrorStatement => 1,
113 FetchHashKeyName => 'NAME_lc',
117 my $master = shift @$_db_params;
118 $master_db = DBI->connect("dbi:Pg:host=$$master{host};dbname=$$master{db}",$$master{user},$$master{pw}, \%attrs);
119 $master_db->do("SET NAMES '$$master{client_encoding}';") if ($$master{client_encoding});
121 $log->debug("Connected to MASTER db '$$master{db} at $$master{host}", INFO);
123 for my $db (@$_db_params) {
124 push @slave_dbs, DBI->connect("dbi:Pg:host=$$db{host};dbname=$$db{db}",$$db{user},$$db{pw}, \%attrs);
125 $slave_dbs[-1]->do("SET NAMES '$$db{client_encoding}';") if ($$master{client_encoding});
127 $log->debug("Connected to MASTER db '$$master{db} at $$master{host}", INFO);
130 $log->debug("All is well on the western front", INTERNAL);
135 return $master_db if ($self->current_xact_session);
136 return $master_db unless (@slave_dbs);
137 return ($master_db, @slave_dbs)[rand(scalar(@slave_dbs))];
142 return $self->db_Main->quote(@_)
145 # sub tsearch2_trigger {
147 # return unless ($self->value);
148 # $self->index_vector(
149 # $self->db_Slaves->selectrow_array(
150 # "SELECT to_tsvector('default',?);",
159 sub current_xact_session {
161 if (defined($_xact_session)) {
162 return $_xact_session;
167 sub current_xact_is_auto {
170 if (defined($_xact_session) and ref($_xact_session)) {
172 $_xact_session->session_data(autocommit => $auto);
174 return $_xact_session->session_data('autocommit');
178 sub current_xact_id {
180 if (defined($_xact_session) and ref($_xact_session)) {
181 return $_xact_session->session_id;
186 sub set_xact_session {
189 if (!defined($ses)) {
192 $_xact_session = $ses;
193 return $_xact_session;
196 sub unset_xact_session {
198 my $ses = $_xact_session;
199 undef $_xact_session;
207 package OpenILS::Application::Storage;
208 use OpenSRF::Utils::Logger;
209 my $log = 'OpenSRF::Utils::Logger';
211 my $pg = 'OpenILS::Application::Storage::Driver::Pg';
213 sub pg_begin_xaction {
217 if (my $old_xact = $pg->current_xact_session) {
218 if ($pg->current_xact_is_auto) {
219 $log->debug("Commiting old autocommit transaction with Open-ILS XACT-ID [$old_xact]", INFO);
220 $self->pg_commit_xaction($client);
222 $log->debug("Rolling back old NON-autocommit transaction with Open-ILS XACT-ID [$old_xact]", INFO);
223 $self->pg_rollback_xaction($client);
224 return new OpenSRF::DomainObject::oilsException (
226 status => "Previous transaction rolled back!",
231 $pg->set_xact_session( $client->session );
232 my $xact_id = $pg->current_xact_id;
234 $log->debug("Beginning a new trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
236 my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
243 $log->debug("Failed to begin a new trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
248 my $death_cb = $client->session->register_callback(
250 __PACKAGE__->pg_rollback_xaction;
254 $log->debug("Registered 'death' callback [$death_cb] for new trasaction with Open-ILS XACT-ID [$xact_id]", DEBUG);
256 $client->session->session_data( death_cb => $death_cb );
258 if ($self->api_name =~ /autocommit$/o) {
259 $pg->current_xact_is_auto(1);
260 my $dc_cb = $client->session->register_callback(
263 $ses->unregister_callback(death => $death_cb);
264 __PACKAGE__->pg_commit_xaction;
267 $log->debug("Registered 'disconnect' callback [$dc_cb] for new trasaction with Open-ILS XACT-ID [$xact_id]", DEBUG);
268 if ($client and $client->session) {
269 $client->session->session_data( disconnect_cb => $dc_cb );
276 __PACKAGE__->register_method(
277 method => 'pg_begin_xaction',
278 api_name => 'open-ils.storage.transaction.begin',
282 __PACKAGE__->register_method(
283 method => 'pg_begin_xaction',
284 api_name => 'open-ils.storage.transaction.begin.autocommit',
289 sub pg_commit_xaction {
294 $log->debug("Committing trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
295 my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
300 $log->debug("Failed to commit trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
304 $pg->current_xact_session->unregister_callback( death =>
305 $pg->current_xact_session->session_data( 'death_cb' )
306 ) if ($pg->current_xact_session);
308 if ($pg->current_xact_is_auto) {
309 $pg->current_xact_session->unregister_callback( disconnect =>
310 $pg->current_xact_session->session_data( 'disconnect_cb' )
314 $pg->unset_xact_session;
319 __PACKAGE__->register_method(
320 method => 'pg_commit_xaction',
321 api_name => 'open-ils.storage.transaction.commit',
326 sub pg_rollback_xaction {
329 my $xact_id = $pg->current_xact_id;
331 my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
332 $log->debug("Rolling back a trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
337 $log->debug("Failed to roll back trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
341 $pg->current_xact_session->unregister_callback( death =>
342 $pg->current_xact_session->session_data( 'death_cb' )
343 ) if ($pg->current_xact_session);
345 if ($pg->current_xact_is_auto) {
346 $pg->current_xact_session->unregister_callback( disconnect =>
347 $pg->current_xact_session->session_data( 'disconnect_cb' )
351 $pg->unset_xact_session;
355 __PACKAGE__->register_method(
356 method => 'pg_rollback_xaction',
357 api_name => 'open-ils.storage.transaction.rollback',
365 #---------------------------------------------------------------------
366 package asset::call_number_note;
368 asset::call_number->table( 'asset.call_number_note' );
369 asset::call_number->sequence( 'asset.call_number_note_id_seq' );
371 #---------------------------------------------------------------------
372 package asset::copy_note;
374 asset::copy->table( 'asset.copy_note' );
375 asset::copy->sequence( 'asset.copy_note_id_seq' );
377 #---------------------------------------------------------------------
378 package asset::call_number;
380 asset::call_number->table( 'asset.call_number' );
381 asset::call_number->sequence( 'asset.call_number_id_seq' );
383 #---------------------------------------------------------------------
386 asset::copy->table( 'asset.copy' );
387 asset::copy->sequence( 'asset.copy_id_seq' );
389 #---------------------------------------------------------------------
390 package biblio::record_entry;
392 biblio::record_entry->table( 'biblio.record_entry' );
393 biblio::record_entry->sequence( 'biblio.record_entry_id_seq' );
395 #---------------------------------------------------------------------
396 package biblio::record_node;
398 biblio::record_node->table( 'biblio.record_data' );
399 biblio::record_node->sequence( 'biblio.record_data_id_seq' );
401 #---------------------------------------------------------------------
402 package biblio::record_marc;
404 biblio::record_marc->table( 'biblio.record_marc' );
405 biblio::record_marc->sequence( 'biblio.record_marc_id_seq' );
407 #---------------------------------------------------------------------
408 package biblio::record_mods;
410 biblio::record_mods->table( 'biblio.record_mods' );
411 biblio::record_mods->sequence( 'biblio.record_mods_id_seq' );
413 #---------------------------------------------------------------------
414 package biblio::record_note;
416 biblio::record_note->table( 'biblio.record_note' );
417 biblio::record_note->sequence( 'biblio.record_note_id_seq' );
419 #---------------------------------------------------------------------
422 actor::user->table( 'actor.usr' );
423 actor::user->sequence( 'actor.usr_id_seq' );
425 #---------------------------------------------------------------------
426 package actor::org_unit_type;
428 actor::org_unit_type->table( 'actor.org_unit_type' );
429 actor::org_unit_type->sequence( 'actor.org_unit_type_id_seq' );
431 #---------------------------------------------------------------------
432 package actor::org_unit;
434 actor::org_unit->table( 'actor.org_unit' );
435 actor::org_unit->sequence( 'actor.org_unit_id_seq' );
437 #---------------------------------------------------------------------
439 #-------------------------------------------------------------------------------
440 package metabib::metarecord;
442 metabib::metarecord->table( 'metabib.metarecord' );
443 metabib::metarecord->sequence( 'metabib.metarecord_id_seq' );
445 #-------------------------------------------------------------------------------
447 #-------------------------------------------------------------------------------
448 package metabib::title_field_entry;
450 metabib::title_field_entry->table( 'metabib.title_field_entry' );
451 metabib::title_field_entry->sequence( 'metabib.title_field_entry_id_seq' );
452 metabib::title_field_entry->columns( 'FTS' => 'index_vector' );
454 # metabib::title_field_entry->add_trigger(
455 # before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
457 # metabib::title_field_entry->add_trigger(
458 # before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
461 #-------------------------------------------------------------------------------
463 #-------------------------------------------------------------------------------
464 package metabib::author_field_entry;
466 metabib::author_field_entry->table( 'metabib.author_field_entry' );
467 metabib::author_field_entry->sequence( 'metabib.author_field_entry_id_seq' );
468 metabib::author_field_entry->columns( 'FTS' => 'index_vector' );
470 #-------------------------------------------------------------------------------
472 #-------------------------------------------------------------------------------
473 package metabib::subject_field_entry;
475 metabib::subject_field_entry->table( 'metabib.subject_field_entry' );
476 metabib::subject_field_entry->sequence( 'metabib.subject_field_entry_id_seq' );
477 metabib::subject_field_entry->columns( 'FTS' => 'index_vector' );
479 #-------------------------------------------------------------------------------
481 #-------------------------------------------------------------------------------
482 package metabib::keyword_field_entry;
484 metabib::keyword_field_entry->table( 'metabib.keyword_field_entry' );
485 metabib::keyword_field_entry->sequence( 'metabib.keyword_field_entry_id_seq' );
486 metabib::keyword_field_entry->columns( 'FTS' => 'index_vector' );
488 #-------------------------------------------------------------------------------
490 #-------------------------------------------------------------------------------
491 package metabib::title_field_entry_source_map;
493 metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map' );
495 #-------------------------------------------------------------------------------
497 #-------------------------------------------------------------------------------
498 package metabib::author_field_entry_source_map;
500 metabib::author_field_entry_source_map->table( 'metabib.author_field_entry_source_map' );
502 #-------------------------------------------------------------------------------
504 #-------------------------------------------------------------------------------
505 package metabib::subject_field_entry_source_map;
507 metabib::subject_field_entry_source_map->table( 'metabib.subject_field_entry_source_map' );
509 #-------------------------------------------------------------------------------
511 #-------------------------------------------------------------------------------
512 package metabib::keyword_field_entry_source_map;
514 metabib::keyword_field_entry_source_map->table( 'metabib.keyword_field_entry_source_map' );
516 #-------------------------------------------------------------------------------
518 #-------------------------------------------------------------------------------
519 package metabib::metarecord_source_map;
521 metabib::metarecord_source_map->table( 'metabib.full_rec' );
523 #-------------------------------------------------------------------------------
525 #-------------------------------------------------------------------------------
526 package metabib::full_rec;
528 metabib::full_rec->table( 'metabib.full_rec' );
529 metabib::full_rec->sequence( 'metabib.full_rec_id_seq' );
530 metabib::full_rec->columns( 'FTS' => 'index_vector' );
532 #-------------------------------------------------------------------------------