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

Last change on this file since 24068 was 24068, checked in by jmt12, 13 years ago

I'm adding the new dynamic form of dbutil.pm here until we are happy to add it to the main trunk of Greenstone. I think David is keener to see the dbutil stuff refactored as OO, whereas this file makes use of PERL black magic to achieve a similar effect in non-OO code

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