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

Last change on this file since 27400 was 27400, checked in by jmt12, 11 years ago

Adding is explanation of server starting up black magic

File size: 9.8 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
97sub open_infodb_write_handle
98{
99 my $infodb_type = shift(@_);
100 my $infodb_file_path = shift(@_);
101 # Make a call to the dynamically loaded driver to open the connection.
102 return &dbutil::call_dynamic_driver_function('open_infodb_write_handle', $infodb_type, $infodb_file_path, @_);
103}
104
105
106sub close_infodb_write_handle
107{
108 my $infodb_type = shift(@_);
109 my $infodb_handle = shift(@_);
110 # Dynamic database driver call
111 return &dbutil::call_dynamic_driver_function('close_infodb_write_handle', $infodb_type, $infodb_handle, @_);
112}
113
114
115sub get_default_infodb_type
116{
117 # The default is GDBM so everything works the same for existing collections
118 # To use something else, specify the "infodbtype" in the collection's collect.cfg file
119 return "gdbm";
120}
121
122# /** @function get_infodb_file_path()
123# * Warning! Black magic follows. The first time get_infodb_file_path is
124# * called (presumably from inexport::process_files()) for databases of type
125# * server will actually the Server to be run complete with an initial dummy
126# * listener. This is done so that, in parallel importing, the server will
127# * persist until the top level import.pl (which will be the first that calls
128# * this function) completes and removes the dummy listener. [jmt12]
129sub get_infodb_file_path
130{
131 my $infodb_type = shift(@_);
132 my $collection_name = shift(@_);
133 my $infodb_directory_path = shift(@_);
134
135 #=======================================MSSQL SUPPORT==============================================#
136 # Updated by Jeffrey (2008/08/25 Monday)
137 # After look into the run-time code, it seems we should still create a database file.
138 # Since the run-time code is always try to read a database file, the easiest way here is not
139 # to change the whole structure, but to give whatever the system is looking for.
140 #==================================================================================================#
141 # Added by Jeffrey (2008/08/15 Friday)
142 # No file path required for MS SQL, it is a server-client connection.
143 # At the moment the information is hard coded in dbutil::mssql::open_infodb_write_handle
144 # the this might need some tidy up sometime.
145 #==================================================================================================#
146
147 return &dbutil::call_dynamic_driver_function('get_infodb_file_path', $infodb_type, $collection_name, $infodb_directory_path, @_);
148}
149
150# This function, conceptually, would be better structured if it didn't
151# use return statements, as the database methods it calls do not
152# themselves return anything.
153# Note: if doing this, then the GDBM lines of code should be moved into
154# an 'else' clause
155sub read_infodb_file
156{
157 my $infodb_type = shift(@_);
158 my $infodb_file_path = shift(@_);
159 my $infodb_map = shift(@_);
160
161 return &dbutil::call_dynamic_driver_function('read_infodb_file', $infodb_type, $infodb_file_path, $infodb_map, @_);
162}
163
164sub read_infodb_keys
165{
166 my $infodb_type = shift(@_);
167 my $infodb_file_path = shift(@_);
168 my $infodb_map = shift(@_);
169
170 return &dbutil::call_dynamic_driver_function('read_infodb_keys', $infodb_type, $infodb_file_path, $infodb_map, @_);
171}
172
173sub write_infodb_entry
174{
175 my $infodb_type = shift(@_);
176 my $infodb_handle = shift(@_);
177 my $infodb_key = shift(@_);
178 my $infodb_map = shift(@_);
179
180 return &dbutil::call_dynamic_driver_function('write_infodb_entry', $infodb_type, $infodb_handle, $infodb_key, $infodb_map, @_);
181}
182
183
184sub write_infodb_rawentry
185{
186 my $infodb_type = shift(@_);
187 my $infodb_handle = shift(@_);
188 my $infodb_key = shift(@_);
189 my $infodb_val = shift(@_);
190
191 return &dbutil::call_dynamic_driver_function('write_infodb_rawentry', $infodb_type, $infodb_handle, $infodb_key, $infodb_val, @_);
192}
193
194
195sub set_infodb_entry
196{
197 my $infodb_type = shift(@_);
198 my $infodb_file_path = shift(@_);
199 my $infodb_key = shift(@_);
200 my $infodb_map = shift(@_);
201
202 return &dbutil::call_dynamic_driver_function('set_infodb_entry', $infodb_type, $infodb_file_path, $infodb_key, $infodb_map, @_);
203}
204
205
206
207sub delete_infodb_entry
208{
209 my $infodb_type = shift(@_);
210 my $infodb_handle = shift(@_);
211 my $infodb_key = shift(@_);
212
213 return &dbutil::call_dynamic_driver_function('delete_infodb_entry', $infodb_type, $infodb_handle, $infodb_key, @_);
214}
215
216sub read_infodb_rawentry
217{
218 my $infodb_type = shift(@_);
219 my $infodb_file_path = shift(@_);
220 my $infodb_key = shift(@_);
221
222 # !! TEMPORARY: Slow and naive implementation that just reads the entire file and picks out the one value
223 # !! This will one day be replaced with database-specific versions that will use dbget etc.
224 my $infodb_map = {};
225 &read_infodb_file($infodb_type, $infodb_file_path, $infodb_map);
226
227 return $infodb_map->{$infodb_key};
228}
229
230
231sub read_infodb_entry
232{
233 my $infodb_type = shift(@_);
234 my $infodb_file_path = shift(@_);
235 my $infodb_key = shift(@_);
236
237 if ($infodb_type eq "sqlite")
238 {
239 require dbutil::sqlite;
240 return &dbutil::sqlite::read_infodb_entry($infodb_file_path, $infodb_key, @_);
241 }
242# elsif ($infodb_type eq "gdbm-txtgz")
243# {
244# require dbutil::gdbmtxtgz;
245# return &dbutil::gdbmtxtgz::read_infodb_entry($infodb_file_path, $infodb_key, @_);
246# }
247# elsif ($infodb_type eq "jdbm")
248# {
249# require dbutil::jdbm;
250# return &dbutil::jdbm::read_infodb_entry($infodb_file_path, $infodb_key, @_);
251# }
252# elsif ($infodb_type eq "mssql")
253# {
254# require dbutil::mssql;
255# return &dbutil::mssql::read_infodb_entry($infodb_file_path, $infodb_key, @_);
256# }
257
258# # Use GDBM if the infodb type is empty or not one of the values above
259# require dbutil::gdbm;
260# return &dbutil::gdbm::read_infodb_entry($infodb_file_path, $infodb_key, @_);
261
262
263 # rawentry above is currently naive implementation
264 my $raw_string = read_infodb_rawentry($infodb_type, $infodb_file_path, $infodb_key);
265 my $infodb_rec = &dbutil::convert_infodb_string_to_hash($raw_string);
266
267 return $infodb_rec;
268}
269
270
271# ---- GENERAL FUNCTIONS --------
272
273sub convert_infodb_hash_to_string
274{
275 my $infodb_map = shift(@_);
276
277 my $infodb_entry_value = "";
278 foreach my $infodb_value_key (keys(%$infodb_map))
279 {
280 foreach my $infodb_value (@{$infodb_map->{$infodb_value_key}})
281 {
282 $infodb_entry_value .= "<$infodb_value_key>" . $infodb_value . "\n";
283 }
284 }
285
286 return $infodb_entry_value;
287}
288
289
290sub convert_infodb_string_to_hash
291{
292 my $infodb_entry_value = shift(@_);
293 my $infodb_map = ();
294
295 if (!defined $infodb_entry_value) {
296 print STDERR "Warning: No value to convert into a infodb hashtable\n";
297 }
298 else {
299 while ($infodb_entry_value =~ /^<(.*?)>(.*)$/mg)
300 {
301 my $infodb_value_key = $1;
302 my $infodb_value = $2;
303
304 if (!defined($infodb_map->{$infodb_value_key}))
305 {
306 $infodb_map->{$infodb_value_key} = [ $infodb_value ];
307 }
308 else
309 {
310 push(@{$infodb_map->{$infodb_value_key}}, $infodb_value);
311 }
312 }
313 }
314
315 return $infodb_map;
316}
317
318
3191;
Note: See TracBrowser for help on using the repository browser.