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);
37 # if (@{$self->nots}) {
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;
84 use OpenILS::Application::Storage::Driver::Pg::cdbi;
85 use OpenILS::Application::Storage::Driver::Pg::fts;
86 use OpenILS::Application::Storage::Driver::Pg::storage;
87 use OpenILS::Application::Storage::Driver::Pg::dbi;
89 use base qw/Class::DBI OpenILS::Application::Storage/;
91 use OpenSRF::EX qw/:try/;
92 use OpenSRF::DomainObject::oilsResponse;
93 use OpenSRF::Utils::Logger qw/:level/;
94 my $log = 'OpenSRF::Utils::Logger';
96 __PACKAGE__->set_sql( retrieve_limited => 'SELECT * FROM __TABLE__ ORDER BY id LIMIT ?' );
97 __PACKAGE__->set_sql( copy_start => 'COPY %s (%s) FROM STDIN;' );
98 __PACKAGE__->set_sql( copy_end => '\.' );
107 $log->debug("Running child_init inside ".__PACKAGE__, INTERNAL);
109 $_db_params = [ $_db_params ] unless (ref($_db_params) eq 'ARRAY');
111 my %attrs = ( %{$self->_default_attributes},
112 RootClass => 'DBIx::ContextualFetch',
113 ShowErrorStatement => 1,
119 FetchHashKeyName => 'NAME_lc',
123 my $master = shift @$_db_params;
124 $master_db = DBI->connect("dbi:Pg:host=$$master{host};dbname=$$master{db}",$$master{user},$$master{pw}, \%attrs);
125 $master_db->do("SET NAMES '$$master{client_encoding}';") if ($$master{client_encoding});
127 $log->debug("Connected to MASTER db '$$master{db} at $$master{host}", INFO);
129 for my $db (@$_db_params) {
130 push @slave_dbs, DBI->connect("dbi:Pg:host=$$db{host};dbname=$$db{db}",$$db{user},$$db{pw}, \%attrs);
131 $slave_dbs[-1]->do("SET NAMES '$$db{client_encoding}';") if ($$master{client_encoding});
133 $log->debug("Connected to MASTER db '$$master{db} at $$master{host}", INFO);
136 $log->debug("All is well on the western front", INTERNAL);
141 return $master_db if ($self->current_xact_session);
142 return $master_db unless (@slave_dbs);
143 return ($master_db, @slave_dbs)[rand(scalar(@slave_dbs))];
148 return $self->db_Main->quote(@_)
151 # sub tsearch2_trigger {
153 # return unless ($self->value);
154 # $self->index_vector(
155 # $self->db_Slaves->selectrow_array(
156 # "SELECT to_tsvector('default',?);",
165 sub current_xact_session {
167 if (defined($_xact_session)) {
168 return $_xact_session;
173 sub current_xact_is_auto {
176 if (defined($_xact_session) and ref($_xact_session)) {
178 $_xact_session->session_data(autocommit => $auto);
180 return $_xact_session->session_data('autocommit');
184 sub current_xact_id {
186 if (defined($_xact_session) and ref($_xact_session)) {
187 return $_xact_session->session_id;
192 sub set_xact_session {
195 if (!defined($ses)) {
198 $_xact_session = $ses;
199 return $_xact_session;
202 sub unset_xact_session {
204 my $ses = $_xact_session;
205 undef $_xact_session;
213 # package OpenILS::Application::Storage;
214 # use OpenSRF::Utils::Logger;
215 # my $log = 'OpenSRF::Utils::Logger';
217 # my $pg = 'OpenILS::Application::Storage::Driver::Pg';
222 # my $client = shift;
223 # return $pg->current_xact_id;
225 # __PACKAGE__->register_method(
226 # method => 'current_xact',
227 # api_name => 'open-ils.storage.transaction.current',
233 # sub pg_begin_xaction {
235 # my $client = shift;
237 # if (my $old_xact = $pg->current_xact_session) {
238 # if ($pg->current_xact_is_auto) {
239 # $log->debug("Commiting old autocommit transaction with Open-ILS XACT-ID [$old_xact]", INFO);
240 # $self->pg_commit_xaction($client);
242 # $log->debug("Rolling back old NON-autocommit transaction with Open-ILS XACT-ID [$old_xact]", INFO);
243 # $self->pg_rollback_xaction($client);
244 # throw OpenSRF::DomainObject::oilsException->new(
246 # status => "Previous transaction rolled back!",
251 # $pg->set_xact_session( $client->session );
252 # my $xact_id = $pg->current_xact_id;
254 # $log->debug("Beginning a new trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
256 # my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
261 # } catch Error with {
263 # $log->debug("Failed to begin a new trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
268 # my $death_cb = $client->session->register_callback(
270 # __PACKAGE__->pg_rollback_xaction;
274 # $log->debug("Registered 'death' callback [$death_cb] for new trasaction with Open-ILS XACT-ID [$xact_id]", DEBUG);
276 # $client->session->session_data( death_cb => $death_cb );
278 # if ($self->api_name =~ /autocommit$/o) {
279 # $pg->current_xact_is_auto(1);
280 # my $dc_cb = $client->session->register_callback(
281 # disconnect => sub {
283 # $ses->unregister_callback(death => $death_cb);
284 # __PACKAGE__->pg_commit_xaction;
287 # $log->debug("Registered 'disconnect' callback [$dc_cb] for new trasaction with Open-ILS XACT-ID [$xact_id]", DEBUG);
288 # if ($client and $client->session) {
289 # $client->session->session_data( disconnect_cb => $dc_cb );
296 # __PACKAGE__->register_method(
297 # method => 'pg_begin_xaction',
298 # api_name => 'open-ils.storage.transaction.begin',
302 # __PACKAGE__->register_method(
303 # method => 'pg_begin_xaction',
304 # api_name => 'open-ils.storage.transaction.begin.autocommit',
309 # sub pg_commit_xaction {
312 # my $xact_id = $pg->current_xact_id;
315 # $log->debug("Committing trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
316 # my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
319 # } catch Error with {
321 # $log->debug("Failed to commit trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
325 # $pg->current_xact_session->unregister_callback( death =>
326 # $pg->current_xact_session->session_data( 'death_cb' )
327 # ) if ($pg->current_xact_session);
329 # if ($pg->current_xact_is_auto) {
330 # $pg->current_xact_session->unregister_callback( disconnect =>
331 # $pg->current_xact_session->session_data( 'disconnect_cb' )
335 # $pg->unset_xact_session;
340 # __PACKAGE__->register_method(
341 # method => 'pg_commit_xaction',
342 # api_name => 'open-ils.storage.transaction.commit',
347 # sub pg_rollback_xaction {
350 # my $xact_id = $pg->current_xact_id;
352 # my $dbh = OpenILS::Application::Storage::CDBI->db_Main;
353 # $log->debug("Rolling back a trasaction with Open-ILS XACT-ID [$xact_id]", INFO);
356 # } catch Error with {
358 # $log->debug("Failed to roll back trasaction with Open-ILS XACT-ID [$xact_id]: ".$e, INFO);
362 # $pg->current_xact_session->unregister_callback( death =>
363 # $pg->current_xact_session->session_data( 'death_cb' )
364 # ) if ($pg->current_xact_session);
366 # if ($pg->current_xact_is_auto) {
367 # $pg->current_xact_session->unregister_callback( disconnect =>
368 # $pg->current_xact_session->session_data( 'disconnect_cb' )
372 # $pg->unset_xact_session;
376 # __PACKAGE__->register_method(
377 # method => 'pg_rollback_xaction',
378 # api_name => 'open-ils.storage.transaction.rollback',
385 # my $client = shift;
388 # return undef unless ($pg->current_xact_session);
390 # my $cdbi = $self->{cdbi};
392 # my $pri = $cdbi->columns('Primary');
394 # my @cols = grep {$_ ne $pri} $cdbi->columns('All');
396 # my $col_list = join ',', @cols;
398 # $log->debug('Starting COPY import for '.$cdbi->table." ($col_list)", DEBUG);
399 # $cdbi->sql_copy_start($cdbi->table, $col_list)->execute;
401 # my $dbh = $cdbi->db_Main;
402 # for my $node ( @fm_nodes ) {
403 # next unless ($node);
404 # my $line = join("\t", map { defined($node->$_()) ? $node->$_() : '\N' } @cols);
405 # $log->debug("COPY line: [$line]",DEBUG);
406 # $dbh->func($line."\n", 'putline');
409 # $dbh->func('endcopy');
411 # return scalar(@fm_nodes);
418 # #---------------------------------------------------------------------
419 # package action::survey;
421 # action::survey->table( 'action.survey' );
422 # action::survey->sequence( 'action.survey_id_seq' );
424 # #---------------------------------------------------------------------
425 # package action::survey_question;
427 # action::survey_question->table( 'action.survey_question' );
428 # action::survey_question->sequence( 'action.survey_question_id_seq' );
430 # #---------------------------------------------------------------------
431 # package action::survey_answer;
433 # action::survey_answer->table( 'action.survey_answer' );
434 # action::survey_answer->sequence( 'action.survey_answer_id_seq' );
436 # #---------------------------------------------------------------------
437 # package action::survey_response;
439 # action::survey_response->table( 'action.survey_response' );
440 # action::survey_response->sequence( 'action.survey_response_id_seq' );
442 # #---------------------------------------------------------------------
443 # package config::copy_status;
445 # config::standing->table( 'config.copy_status' );
446 # config::standing->sequence( 'config.copy_status_id_seq' );
448 # #---------------------------------------------------------------------
449 # package config::net_access_level;
451 # config::standing->table( 'config.net_access_level' );
452 # config::standing->sequence( 'config.net_access_level_id_seq' );
454 # #---------------------------------------------------------------------
455 # package config::standing;
457 # config::standing->table( 'config.standing' );
458 # config::standing->sequence( 'config.standing_id_seq' );
460 # #---------------------------------------------------------------------
461 # package config::metabib_field;
463 # config::metabib_field->table( 'config.metabib_field' );
464 # config::metabib_field->sequence( 'config.metabib_field_id_seq' );
466 # #---------------------------------------------------------------------
467 # package config::bib_source;
469 # config::bib_source->table( 'config.bib_source' );
470 # config::bib_source->sequence( 'config.bib_source_id_seq' );
472 # #---------------------------------------------------------------------
473 # package config::identification_type;
475 # config::identification_type->table( 'config.identification_type' );
476 # config::identification_type->sequence( 'config.identification_type_id_seq' );
478 # #---------------------------------------------------------------------
479 # package asset::call_number_note;
481 # asset::call_number->table( 'asset.call_number_note' );
482 # asset::call_number->sequence( 'asset.call_number_note_id_seq' );
484 # #---------------------------------------------------------------------
485 # package asset::copy_note;
487 # asset::copy->table( 'asset.copy_note' );
488 # asset::copy->sequence( 'asset.copy_note_id_seq' );
490 # #---------------------------------------------------------------------
491 # package asset::call_number;
493 # asset::call_number->table( 'asset.call_number' );
494 # asset::call_number->sequence( 'asset.call_number_id_seq' );
496 # #---------------------------------------------------------------------
497 # package asset::copy_location;
499 # asset::copy->table( 'asset.copy_location' );
500 # asset::copy->sequence( 'asset.copy_location_id_seq' );
502 # #---------------------------------------------------------------------
503 # package asset::copy;
505 # asset::copy->table( 'asset.copy' );
506 # asset::copy->sequence( 'asset.copy_id_seq' );
508 # #---------------------------------------------------------------------
509 # package asset::stat_cat;
511 # asset::stat_cat->table( 'asset.stat_cat' );
512 # asset::stat_cat->sequence( 'asset.stat_cat_id_seq' );
514 # #---------------------------------------------------------------------
515 # package asset::stat_cat_entry;
517 # asset::stat_cat_entry->table( 'asset.stat_cat_entry' );
518 # asset::stat_cat_entry->sequence( 'asset.stat_cat_entry_id_seq' );
520 # #---------------------------------------------------------------------
521 # package asset::stat_cat_entry_copy_map;
523 # asset::stat_cat_entry_copy_map->table( 'asset.stat_cat_entry_copy_map' );
524 # asset::stat_cat_entry_copy_map->sequence( 'asset.stat_cat_entry_copy_map_id_seq' );
526 # #---------------------------------------------------------------------
527 # package biblio::record_entry;
529 # biblio::record_entry->table( 'biblio.record_entry' );
530 # biblio::record_entry->sequence( 'biblio.record_entry_id_seq' );
532 # #---------------------------------------------------------------------
533 # #package biblio::record_marc;
535 # #biblio::record_marc->table( 'biblio.record_marc' );
536 # #biblio::record_marc->sequence( 'biblio.record_marc_id_seq' );
538 # #---------------------------------------------------------------------
539 # package biblio::record_note;
541 # biblio::record_note->table( 'biblio.record_note' );
542 # biblio::record_note->sequence( 'biblio.record_note_id_seq' );
544 # #---------------------------------------------------------------------
545 # package actor::user;
547 # actor::user->table( 'actor.usr' );
548 # actor::user->sequence( 'actor.usr_id_seq' );
550 # #---------------------------------------------------------------------
551 # package actor::user_address;
553 # actor::user_address->table( 'actor.usr_address' );
554 # actor::user_address->sequence( 'actor.usr_address_id_seq' );
556 # #---------------------------------------------------------------------
557 # package actor::org_address;
559 # actor::org_address->table( 'actor.org_address' );
560 # actor::org_address->sequence( 'actor.org_address_id_seq' );
562 # #---------------------------------------------------------------------
563 # package actor::profile;
565 # actor::profile->table( 'actor.profile' );
566 # actor::profile->sequence( 'actor.profile_id_seq' );
568 # #---------------------------------------------------------------------
569 # package actor::org_unit_type;
571 # actor::org_unit_type->table( 'actor.org_unit_type' );
572 # actor::org_unit_type->sequence( 'actor.org_unit_type_id_seq' );
574 # #---------------------------------------------------------------------
575 # package actor::org_unit;
577 # actor::org_unit->table( 'actor.org_unit' );
578 # actor::org_unit->sequence( 'actor.org_unit_id_seq' );
580 # #---------------------------------------------------------------------
581 # package actor::stat_cat;
583 # actor::stat_cat->table( 'actor.stat_cat' );
584 # actor::stat_cat->sequence( 'actor.stat_cat_id_seq' );
586 # #---------------------------------------------------------------------
587 # package actor::stat_cat_entry;
589 # actor::stat_cat_entry->table( 'actor.stat_cat_entry' );
590 # actor::stat_cat_entry->sequence( 'actor.stat_cat_entry_id_seq' );
592 # #---------------------------------------------------------------------
593 # package actor::stat_cat_entry_user_map;
595 # actor::stat_cat_entry_user_map->table( 'actor.stat_cat_entry_copy_map' );
596 # actor::stat_cat_entry_user_map->sequence( 'actor.stat_cat_entry_usr_map_id_seq' );
598 # #---------------------------------------------------------------------
599 # package actor::card;
601 # actor::card->table( 'actor.card' );
602 # actor::card->sequence( 'actor.card_id_seq' );
604 # #---------------------------------------------------------------------
606 # #-------------------------------------------------------------------------------
607 # package metabib::metarecord;
609 # metabib::metarecord->table( 'metabib.metarecord' );
610 # metabib::metarecord->sequence( 'metabib.metarecord_id_seq' );
612 # OpenILS::Application::Storage->register_method(
613 # api_name => 'open-ils.storage.direct.metabib.metarecord.batch.create',
614 # method => 'copy_create',
616 # 'package' => 'OpenILS::Application::Storage',
617 # cdbi => 'metabib::metarecord',
621 # #-------------------------------------------------------------------------------
623 # #-------------------------------------------------------------------------------
624 # package metabib::title_field_entry;
626 # metabib::title_field_entry->table( 'metabib.title_field_entry' );
627 # metabib::title_field_entry->sequence( 'metabib.title_field_entry_id_seq' );
628 # metabib::title_field_entry->columns( 'FTS' => 'index_vector' );
630 ## metabib::title_field_entry->add_trigger(
631 ## before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
633 ## metabib::title_field_entry->add_trigger(
634 ## before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
637 # OpenILS::Application::Storage->register_method(
638 # api_name => 'open-ils.storage.direct.metabib.title_field_entry.batch.create',
639 # method => 'copy_create',
641 # 'package' => 'OpenILS::Application::Storage',
642 # cdbi => 'metabib::title_field_entry',
645 # #-------------------------------------------------------------------------------
647 # #-------------------------------------------------------------------------------
648 # package metabib::author_field_entry;
650 # metabib::author_field_entry->table( 'metabib.author_field_entry' );
651 # metabib::author_field_entry->sequence( 'metabib.author_field_entry_id_seq' );
652 # metabib::author_field_entry->columns( 'FTS' => 'index_vector' );
654 # OpenILS::Application::Storage->register_method(
655 # api_name => 'open-ils.storage.direct.metabib.author_field_entry.batch.create',
656 # method => 'copy_create',
658 # 'package' => 'OpenILS::Application::Storage',
659 # cdbi => 'metabib::author_field_entry',
662 # #-------------------------------------------------------------------------------
664 # #-------------------------------------------------------------------------------
665 # package metabib::subject_field_entry;
667 # metabib::subject_field_entry->table( 'metabib.subject_field_entry' );
668 # metabib::subject_field_entry->sequence( 'metabib.subject_field_entry_id_seq' );
669 # metabib::subject_field_entry->columns( 'FTS' => 'index_vector' );
671 # OpenILS::Application::Storage->register_method(
672 # api_name => 'open-ils.storage.direct.metabib.subject_field_entry.batch.create',
673 # method => 'copy_create',
675 # 'package' => 'OpenILS::Application::Storage',
676 # cdbi => 'metabib::subject_field_entry',
679 # #-------------------------------------------------------------------------------
681 # #-------------------------------------------------------------------------------
682 # package metabib::keyword_field_entry;
684 # metabib::keyword_field_entry->table( 'metabib.keyword_field_entry' );
685 # metabib::keyword_field_entry->sequence( 'metabib.keyword_field_entry_id_seq' );
686 # metabib::keyword_field_entry->columns( 'FTS' => 'index_vector' );
688 # OpenILS::Application::Storage->register_method(
689 # api_name => 'open-ils.storage.direct.metabib.keyword_field_entry.batch.create',
690 # method => 'copy_create',
692 # 'package' => 'OpenILS::Application::Storage',
693 # cdbi => 'metabib::keyword_field_entry',
696 # #-------------------------------------------------------------------------------
698 # #-------------------------------------------------------------------------------
699 # #package metabib::title_field_entry_source_map;
701 # #metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map' );
703 # #-------------------------------------------------------------------------------
705 # #-------------------------------------------------------------------------------
706 # #package metabib::author_field_entry_source_map;
708 # #metabib::author_field_entry_source_map->table( 'metabib.author_field_entry_source_map' );
710 # #-------------------------------------------------------------------------------
712 # #-------------------------------------------------------------------------------
713 # #package metabib::subject_field_entry_source_map;
715 # #metabib::subject_field_entry_source_map->table( 'metabib.subject_field_entry_source_map' );
717 # #-------------------------------------------------------------------------------
719 # #-------------------------------------------------------------------------------
720 # #package metabib::keyword_field_entry_source_map;
722 # #metabib::keyword_field_entry_source_map->table( 'metabib.keyword_field_entry_source_map' );
724 # #-------------------------------------------------------------------------------
726 # #-------------------------------------------------------------------------------
727 # package metabib::metarecord_source_map;
729 # metabib::metarecord_source_map->table( 'metabib.metarecord_source_map' );
730 # OpenILS::Application::Storage->register_method(
731 # api_name => 'open-ils.storage.direct.metabib.metarecord_source_map.batch.create',
732 # method => 'copy_create',
734 # 'package' => 'OpenILS::Application::Storage',
735 # cdbi => 'metabib::metarecord_source_map',
739 # #-------------------------------------------------------------------------------
740 # package metabib::record_descriptor;
742 # metabib::record_descriptor->table( 'metabib.rec_descriptor' );
743 # metabib::record_descriptor->sequence( 'metabib.rec_descriptor_id_seq' );
745 # OpenILS::Application::Storage->register_method(
746 # api_name => 'open-ils.storage.direct.metabib.record_descriptor.batch.create',
747 # method => 'copy_create',
749 # 'package' => 'OpenILS::Application::Storage',
750 # cdbi => 'metabib::record_descriptor',
753 # #-------------------------------------------------------------------------------
756 # #-------------------------------------------------------------------------------
757 # package metabib::full_rec;
759 # metabib::full_rec->table( 'metabib.full_rec' );
760 # metabib::full_rec->sequence( 'metabib.full_rec_id_seq' );
761 # metabib::full_rec->columns( 'FTS' => 'index_vector' );
763 # OpenILS::Application::Storage->register_method(
764 # api_name => 'open-ils.storage.direct.metabib.full_rec.batch.create',
765 # method => 'copy_create',
767 # 'package' => 'OpenILS::Application::Storage',
768 # cdbi => 'metabib::full_rec',
772 # #-------------------------------------------------------------------------------