]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Storage/Driver/Pg.pm
building my own replication stuff, damn it!
[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::Replication;
64         use base qw/Class::DBI OpenILS::Application::Storage/;
65         use DBI;
66         use OpenSRF::EX qw/:try/;
67         use OpenSRF::Utils::Logger qw/:level/;
68         my $log = 'OpenSRF::Utils::Logger';
69
70         __PACKAGE__->set_sql( retrieve_limited => 'SELECT * FROM __TABLE__ ORDER BY id LIMIT ?' );
71
72         my $master_db;
73         my @slave_dbs;
74         my $_db_params;
75         sub child_init {
76                 my $self = shift;
77                 $_db_params = shift;
78
79                 $log->debug("Running child_init inside ".__PACKAGE__, INTERNAL);
80
81                 $_db_params = [ $_db_params ] unless (ref($_db_params) eq 'ARRAY');
82
83                 my %attrs = (   %{$self->_default_attributes},
84                                 RootClass => 'DBIx::ContextualFetch',
85                                 ShowErrorStatement => 1,
86                                 RaiseError => 1,
87                                 AutoCommit => 1,
88                                 PrintError => 1,
89                                 Taint => 1,
90                                 pg_enable_utf8 => 1,
91                                 FetchHashKeyName => 'NAME_lc',
92                                 ChopBlanks => 1,
93                 );
94
95                 my $master = shift @$_db_params;
96                 $master_db = DBI->connect("dbi:Pg:host=$$master{host};dbname=$$master{db}",$$master{user},$$master{pw}, \%attrs);
97
98                 $log->debug("Connected to MASTER db at $$master{host}", INTERNAL);
99                 
100                 for my $db (@$_db_params) {
101                         push @slave_dbs, DBI->connect("dbi:Pg:host=$$db{host};dbname=$$db{db}",$$db{user},$$db{pw}, \%attrs);
102                 }
103
104                 $log->debug("All is well on the western front", INTERNAL);
105         }
106
107         sub db_Main {
108                 my $self = shift;
109                 return $master_db if ($self->current_xact_session);
110                 return $master_db unless (@slave_dbs);
111                 return ($master_db, @slave_dbs)[rand(scalar(@slave_dbs))];
112         }
113
114         sub quote {
115                 return __PACKAGE__->db_Main->quote(@_)
116         }
117
118         sub tsearch2_trigger {
119                 my $self = shift;
120                 return unless ($self->value);
121                 $self->index_vector(
122                         $self->db_Slaves->selectrow_array(
123                                 "SELECT to_tsvector('default',?);",
124                                 {},
125                                 $self->value
126                         )
127                 );
128         }
129
130         my $_xact_session;
131         sub current_xact_session {
132                 my $self = shift;
133                 my $ses = shift;
134                 $_xact_session = $ses if (defined $ses);
135                 return $_xact_session;
136         }
137
138 }
139
140
141 {
142         package OpenILS::Application::Storage;
143
144         sub pg_begin_xaction {
145                 my $self = shift;
146                 my $client = shift;
147
148                 OpenILS::Application::Storage::Driver::Pg->current_xact_session( $client->session->session_id );
149
150                 $client->session->register_callback( disconnect => sub { __PACKAGE__->pg_commit_xaction($client); } )
151                         if ($self->api_name =~ /autocommit$/o);
152
153                 $client->session->register_callback( death => sub { __PACKAGE__->pg_rollback_xaction($client); } );
154
155                 return $self->begin_xaction;
156         }
157         __PACKAGE__->register_method(
158                 method          => 'pg_begin_xaction',
159                 api_name        => 'open-ils.storage.transaction.begin',
160                 api_level       => 1,
161                 argc            => 0,
162         );
163         __PACKAGE__->register_method(
164                 method          => 'pg_begin_xaction',
165                 api_name        => 'open-ils.storage.transaction.begin.autocommit',
166                 api_level       => 1,
167                 argc            => 0,
168         );
169
170         sub pg_commit_xaction {
171
172                 OpenILS::Application::Storage::Driver::Pg->current_xact_session( 0 );
173                 return $self->commit_xaction(@_);
174         }
175         __PACKAGE__->register_method(
176                 method          => 'pg_commit_xaction',
177                 api_name        => 'open-ils.storage.transaction.commit',
178                 api_level       => 1,
179                 argc            => 0,
180         );
181
182         sub pg_rollback_xaction {
183
184                 OpenILS::Application::Storage::Driver::Pg->current_xact_session( 0 );
185                 return $self->rollback_xaction(@_);
186         }
187         __PACKAGE__->register_method(
188                 method          => 'pg_rollback_xaction',
189                 api_name        => 'open-ils.storage.transaction.rollback',
190                 api_level       => 1,
191                 argc            => 0,
192         );
193
194 }
195
196 {
197         #---------------------------------------------------------------------
198         package asset::call_number;
199         
200         asset::call_number->table( 'asset.call_number' );
201         asset::call_number->sequence( 'asset.call_number_id_seq' );
202         
203         #---------------------------------------------------------------------
204         package asset::copy;
205         
206         asset::copy->table( 'asset.copy' );
207         asset::copy->sequence( 'asset.copy_id_seq' );
208         
209         #---------------------------------------------------------------------
210         package biblio::record_entry;
211         
212         biblio::record_entry->table( 'biblio.record_entry' );
213         biblio::record_entry->sequence( 'biblio.record_entry_id_seq' );
214
215         #---------------------------------------------------------------------
216         package biblio::record_node;
217         
218         biblio::record_node->table( 'biblio.record_data' );
219         biblio::record_node->sequence( 'biblio.record_data_id_seq' );
220         
221         #---------------------------------------------------------------------
222         package biblio::record_note;
223         
224         biblio::record_note->table( 'biblio.record_note' );
225         biblio::record_note->sequence( 'biblio.record_note_id_seq' );
226         
227         #---------------------------------------------------------------------
228         package actor::user;
229         
230         actor::user->table( 'actor.usr' );
231         actor::user->sequence( 'actor.usr_id_seq' );
232         
233         #---------------------------------------------------------------------
234         package actor::org_unit_type;
235         
236         actor::org_unit_type->table( 'actor.org_unit_type' );
237         actor::org_unit_type->sequence( 'actor.org_unit_type_id_seq' );
238         
239         #---------------------------------------------------------------------
240         
241         #-------------------------------------------------------------------------------
242         package metabib::metarecord;
243
244         metabib::metarecord->table( 'metabib.metarecord' );
245         metabib::metarecord->sequence( 'metabib.metarecord_id_seq' );
246
247         #-------------------------------------------------------------------------------
248
249         #-------------------------------------------------------------------------------
250         package metabib::title_field_entry;
251
252         metabib::title_field_entry->table( 'metabib.title_field_entry' );
253         metabib::title_field_entry->sequence( 'metabib.title_field_entry_id_seq' );
254         metabib::title_field_entry->columns( Primary => qw/id/ );
255         metabib::title_field_entry->columns( Essential => qw/id/ );
256         metabib::title_field_entry->columns( Others => qw/field value index_vector/ );
257
258         metabib::title_field_entry->add_trigger(
259                 before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
260         );
261         metabib::title_field_entry->add_trigger(
262                 before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
263         );
264
265         #-------------------------------------------------------------------------------
266
267         #-------------------------------------------------------------------------------
268         package metabib::author_field_entry;
269
270         metabib::author_field_entry->table( 'metabib.author_field_entry' );
271         metabib::author_field_entry->sequence( 'metabib.author_field_entry_id_seq' );
272
273         metabib::author_field_entry->add_trigger(
274                 before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
275         );
276         metabib::author_field_entry->add_trigger(
277                 before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
278         );
279
280         #-------------------------------------------------------------------------------
281
282         #-------------------------------------------------------------------------------
283         package metabib::subject_field_entry;
284
285         metabib::subject_field_entry->table( 'metabib.subject_field_entry' );
286         metabib::subject_field_entry->sequence( 'metabib.subject_field_entry_id_seq' );
287
288         metabib::subject_field_entry->add_trigger(
289                 before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
290         );
291         metabib::subject_field_entry->add_trigger(
292                 before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
293         );
294
295         #-------------------------------------------------------------------------------
296
297         #-------------------------------------------------------------------------------
298         package metabib::keyword_field_entry;
299
300         metabib::keyword_field_entry->table( 'metabib.keyword_field_entry' );
301         metabib::keyword_field_entry->sequence( 'metabib.keyword_field_entry_id_seq' );
302
303         metabib::keyword_field_entry->add_trigger(
304                 before_create => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
305         );
306         metabib::keyword_field_entry->add_trigger(
307                 before_update => \&OpenILS::Application::Storage::Driver::Pg::tsearch2_trigger
308         );
309
310         #-------------------------------------------------------------------------------
311
312         #-------------------------------------------------------------------------------
313         package metabib::title_field_entry_source_map;
314
315         metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map' );
316         metabib::title_field_entry_source_map->table( 'metabib.title_field_entry_source_map_id_seq' );
317
318         #-------------------------------------------------------------------------------
319
320         #-------------------------------------------------------------------------------
321         package metabib::author_field_entry_source_map;
322
323         metabib::author_field_entry_source_map->table( 'metabib.author_field_entry_source_map' );
324         metabib::author_field_entry_source_map->sequence( 'metabib.author_field_entry_source_map_id_seq' );
325
326         #-------------------------------------------------------------------------------
327
328         #-------------------------------------------------------------------------------
329         package metabib::subject_field_entry_source_map;
330
331         metabib::subject_field_entry_source_map->table( 'metabib.subject_field_entry_source_map' );
332         metabib::subject_field_entry_source_map->sequence( 'metabib.subject_field_entry_source_map_id_seq' );
333
334         #-------------------------------------------------------------------------------
335 }
336
337 1;