source: gs2-extensions/tdb-edit/trunk/src/perllib/dbutil.pm@ 28000

Last change on this file since 28000 was 28000, checked in by jmt12, 8 years ago

Functions for determining if the plugout supports writing Datestamp and RSS information internally (or if Greenstone should handle writing them itself)

File size: 11.1 KB
Line 
1###########################################################################
2#
3# dbutil.pm -- gateway to utilities for reading/writing to different databases
4#
5# Copyright (C) 2008 DL Consulting Ltd
6#
7# A component of the Greenstone digital library software
8# from the New Zealand Digital Library Project at the
9# University of Waikato, New Zealand.
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24#
25###########################################################################
26
27package dbutil;
28
29use strict;
30
31use Symbol qw<qualify>;
32use util;
33
34# /** Dynamic class loading - for use in DBUtils to load various database
35# * drivers, configured in the collect.cfg, at runtime.
36# * @param $class - The class name (including any path) to load
37# * @param rest - any function aliases you want exported
38# */
39sub load_db_driver
40{
41 my $class = shift(@_);
42 (my $file = "$class.pm") =~ s|::|/|g;
43 # - ensure we haven't already loaded this class
44 unless( $INC{$file} )
45 {
46 # - require is fine being assigned at runtime - no need for evil eval
47 #eval
48 #{
49 require $file;
50 #};
51 }
52 # - this is the magic that actually instantiates the class (rubberstamp?)
53 # - we pass @_ to action any function aliases exports requested
54 eval
55 {
56 $class->import(@_);
57 };
58 # - by now the driver file should have been loaded
59 return (defined $INC{$file});
60}
61# /** load_db_driver() **/
62
63# /** Make a function call to a dynamically loaded database driver.
64# * @param $function_name
65# * @param $driver_name
66# * @param <rest> The parameters to be passed to the function called
67# */
68sub call_dynamic_driver_function
69{
70 my $function_name = shift(@_);
71 my $driver_name = shift(@_);
72 my $package_name = 'dbutil::' . $driver_name;
73 # - try to load the requested infodb type
74 if (!&load_db_driver($package_name))
75 {
76 # - try loading the default GDBM driver
77 print STDERR 'Warning! Using default database driver (GDBM) as failed to load configured database driver: ' . $driver_name . "\n";
78 $package_name = 'dbutil::gdbm';
79 if (!&load_db_driver($package_name))
80 {
81 die("Fatal Error! Failed to load default database driver: dbutil::gdbm\n");
82 }
83 }
84 # - make call to the newly created package
85 no strict;
86 # - lets check that the function we are about to call
87 my $symbol = qualify($function_name, $package_name);
88 unless ( defined &{$symbol} )
89 {
90 die ('Error! Function not found: ' . $package_name . '::' . $function_name . "()\n");
91 }
92 return &{$symbol}(@_);
93}
94# /** call_dynamic_driver_function() **/
95
96
97## @function test_dynamic_driver_function()
98#
99# Checks to see if a function in a dynamically loaded driver exists
100#
101sub test_dynamic_driver_function
102{
103 my $function_name = shift(@_);
104 my $driver_name = shift(@_);
105 my $package_name = 'dbutil::' . $driver_name;
106 # - try to load the requested infodb type
107 if (!&load_db_driver($package_name))
108 {
109 # - try loading the default GDBM driver
110 print STDERR 'Warning! Using default database driver (GDBM) as failed to load configured database driver: ' . $driver_name . "\n";
111 $package_name = 'dbutil::gdbm';
112 if (!&load_db_driver($package_name))
113 {
114 die("Fatal Error! Failed to load default database driver: dbutil::gdbm\n");
115 }
116 }
117 # - make call to the newly created package
118 no strict;
119 # - lets check that the function we are about to call
120 my $symbol = qualify($function_name, $package_name);
121 return defined &{$symbol};
122}
123## test_dynamic_driver_function() ##
124
125
126## @function
127#
128sub open_infodb_write_handle
129{
130 my $infodb_type = shift(@_);
131 my $infodb_file_path = shift(@_);
132 # Make a call to the dynamically loaded driver to open the connection.
133 return &dbutil::call_dynamic_driver_function('open_infodb_write_handle', $infodb_type, $infodb_file_path, @_);
134}
135
136
137sub close_infodb_write_handle
138{
139 my $infodb_type = shift(@_);
140 my $infodb_handle = shift(@_);
141 # Dynamic database driver call
142 return &dbutil::call_dynamic_driver_function('close_infodb_write_handle', $infodb_type, $infodb_handle, @_);
143}
144
145
146sub get_default_infodb_type
147{
148 # The default is GDBM so everything works the same for existing collections
149 # To use something else, specify the "infodbtype" in the collection's collect.cfg file
150 return "gdbm";
151}
152
153# /** @function get_infodb_file_path()
154# * Warning! Black magic follows. The first time get_infodb_file_path is
155# * called (presumably from inexport::process_files()) for databases of type
156# * server will actually the Server to be run complete with an initial dummy
157# * listener. This is done so that, in parallel importing, the server will
158# * persist until the top level import.pl (which will be the first that calls
159# * this function) completes and removes the dummy listener. [jmt12]
160sub get_infodb_file_path
161{
162 my $infodb_type = shift(@_);
163 my $collection_name = shift(@_);
164 my $infodb_directory_path = shift(@_);
165
166 #=======================================MSSQL SUPPORT==============================================#
167 # Updated by Jeffrey (2008/08/25 Monday)
168 # After look into the run-time code, it seems we should still create a database file.
169 # Since the run-time code is always try to read a database file, the easiest way here is not
170 # to change the whole structure, but to give whatever the system is looking for.
171 #==================================================================================================#
172 # Added by Jeffrey (2008/08/15 Friday)
173 # No file path required for MS SQL, it is a server-client connection.
174 # At the moment the information is hard coded in dbutil::mssql::open_infodb_write_handle
175 # the this might need some tidy up sometime.
176 #==================================================================================================#
177
178 return &dbutil::call_dynamic_driver_function('get_infodb_file_path', $infodb_type, $collection_name, $infodb_directory_path, @_);
179}
180
181# This function, conceptually, would be better structured if it didn't
182# use return statements, as the database methods it calls do not
183# themselves return anything.
184# Note: if doing this, then the GDBM lines of code should be moved into
185# an 'else' clause
186sub read_infodb_file
187{
188 my $infodb_type = shift(@_);
189 my $infodb_file_path = shift(@_);
190 my $infodb_map = shift(@_);
191
192 return &dbutil::call_dynamic_driver_function('read_infodb_file', $infodb_type, $infodb_file_path, $infodb_map, @_);
193}
194
195sub read_infodb_keys
196{
197 my $infodb_type = shift(@_);
198 my $infodb_file_path = shift(@_);
199 my $infodb_map = shift(@_);
200
201 return &dbutil::call_dynamic_driver_function('read_infodb_keys', $infodb_type, $infodb_file_path, $infodb_map, @_);
202}
203
204
205## @function supportDatestamp
206#
207sub supportsDatestamp
208{
209 my $infodb_type = shift(@_);
210 return &dbutil::test_dynamic_driver_function('supportsDatestamp', $infodb_type);
211}
212## supportsDatestamp() ##
213
214
215## @function supportRSS
216#
217sub supportsRSS
218{
219 my $infodb_type = shift(@_);
220 return &dbutil::test_dynamic_driver_function('supportsRSS', $infodb_type);
221}
222## supportsRSS() ##
223
224
225sub write_infodb_entry
226{
227 my $infodb_type = shift(@_);
228 my $infodb_handle = shift(@_);
229 my $infodb_key = shift(@_);
230 my $infodb_map = shift(@_);
231
232 return &dbutil::call_dynamic_driver_function('write_infodb_entry', $infodb_type, $infodb_handle, $infodb_key, $infodb_map, @_);
233}
234
235
236sub write_infodb_rawentry
237{
238 my $infodb_type = shift(@_);
239 my $infodb_handle = shift(@_);
240 my $infodb_key = shift(@_);
241 my $infodb_val = shift(@_);
242
243 return &dbutil::call_dynamic_driver_function('write_infodb_rawentry', $infodb_type, $infodb_handle, $infodb_key, $infodb_val, @_);
244}
245
246
247sub set_infodb_entry
248{
249 my $infodb_type = shift(@_);
250 my $infodb_file_path = shift(@_);
251 my $infodb_key = shift(@_);
252 my $infodb_map = shift(@_);
253
254 return &dbutil::call_dynamic_driver_function('set_infodb_entry', $infodb_type, $infodb_file_path, $infodb_key, $infodb_map, @_);
255}
256
257
258
259sub delete_infodb_entry
260{
261 my $infodb_type = shift(@_);
262 my $infodb_handle = shift(@_);
263 my $infodb_key = shift(@_);
264
265 return &dbutil::call_dynamic_driver_function('delete_infodb_entry', $infodb_type, $infodb_handle, $infodb_key, @_);
266}
267
268sub read_infodb_rawentry
269{
270 my $infodb_type = shift(@_);
271 my $infodb_file_path = shift(@_);
272 my $infodb_key = shift(@_);
273
274 # !! TEMPORARY: Slow and naive implementation that just reads the entire file and picks out the one value
275 # !! This will one day be replaced with database-specific versions that will use dbget etc.
276 my $infodb_map = {};
277 &read_infodb_file($infodb_type, $infodb_file_path, $infodb_map);
278
279 return $infodb_map->{$infodb_key};
280}
281
282
283sub read_infodb_entry
284{
285 my $infodb_type = shift(@_);
286 my $infodb_file_path = shift(@_);
287 my $infodb_key = shift(@_);
288
289 if ($infodb_type eq "sqlite")
290 {
291 require dbutil::sqlite;
292 return &dbutil::sqlite::read_infodb_entry($infodb_file_path, $infodb_key, @_);
293 }
294# elsif ($infodb_type eq "gdbm-txtgz")
295# {
296# require dbutil::gdbmtxtgz;
297# return &dbutil::gdbmtxtgz::read_infodb_entry($infodb_file_path, $infodb_key, @_);
298# }
299# elsif ($infodb_type eq "jdbm")
300# {
301# require dbutil::jdbm;
302# return &dbutil::jdbm::read_infodb_entry($infodb_file_path, $infodb_key, @_);
303# }
304# elsif ($infodb_type eq "mssql")
305# {
306# require dbutil::mssql;
307# return &dbutil::mssql::read_infodb_entry($infodb_file_path, $infodb_key, @_);
308# }
309
310# # Use GDBM if the infodb type is empty or not one of the values above
311# require dbutil::gdbm;
312# return &dbutil::gdbm::read_infodb_entry($infodb_file_path, $infodb_key, @_);
313
314
315 # rawentry above is currently naive implementation
316 my $raw_string = read_infodb_rawentry($infodb_type, $infodb_file_path, $infodb_key);
317 my $infodb_rec = &dbutil::convert_infodb_string_to_hash($raw_string);
318
319 return $infodb_rec;
320}
321
322
323# ---- GENERAL FUNCTIONS --------
324
325sub convert_infodb_hash_to_string
326{
327 my $infodb_map = shift(@_);
328
329 my $infodb_entry_value = "";
330 foreach my $infodb_value_key (keys(%$infodb_map))
331 {
332 foreach my $infodb_value (@{$infodb_map->{$infodb_value_key}})
333 {
334 $infodb_entry_value .= "<$infodb_value_key>" . $infodb_value . "\n";
335 }
336 }
337
338 return $infodb_entry_value;
339}
340
341
342sub convert_infodb_string_to_hash
343{
344 my $infodb_entry_value = shift(@_);
345 my $infodb_map = ();
346
347 if (!defined $infodb_entry_value) {
348 print STDERR "Warning: No value to convert into a infodb hashtable\n";
349 }
350 else {
351 while ($infodb_entry_value =~ /^<(.*?)>(.*)$/mg)
352 {
353 my $infodb_value_key = $1;
354 my $infodb_value = $2;
355
356 if (!defined($infodb_map->{$infodb_value_key}))
357 {
358 $infodb_map->{$infodb_value_key} = [ $infodb_value ];
359 }
360 else
361 {
362 push(@{$infodb_map->{$infodb_value_key}}, $infodb_value);
363 }
364 }
365 }
366
367 return $infodb_map;
368}
369
370
3711;
Note: See TracBrowser for help on using the repository browser.