line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=pod
|
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
DB_File::DB_Database - Perl module for reading and writing the DB_File data as a mutifield table
|
6
|
|
|
|
|
|
|
with index file supported.
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=cut
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# ############
|
11
|
|
|
|
|
|
|
package DB_File::DB_Database;
|
12
|
|
|
|
|
|
|
|
13
|
2
|
|
|
2
|
|
3533
|
use 5.004;
|
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
177
|
|
14
|
2
|
|
|
2
|
|
14
|
use strict;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
72
|
|
15
|
2
|
|
|
2
|
|
1036
|
use DB_File;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
use Fcntl qw( O_RDWR O_RDONLY LOCK_SH LOCK_EX LOCK_UN);
|
17
|
|
|
|
|
|
|
# ##############
|
18
|
|
|
|
|
|
|
# General things
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
use vars qw( $VERSION $errstr @ISA );
|
21
|
|
|
|
|
|
|
$VERSION = 0.031;
|
22
|
|
|
|
|
|
|
# Sets the debug level
|
23
|
|
|
|
|
|
|
$DB_File::DB_Database::DEBUG = 0;
|
24
|
|
|
|
|
|
|
BEGIN {
|
25
|
|
|
|
|
|
|
if ($^O =~ /mswin/i) { $DB_File::DB_Database::LOCKING = 0; }
|
26
|
|
|
|
|
|
|
else { $DB_File::DB_Database::LOCKING = 1; }
|
27
|
|
|
|
|
|
|
require IO::File if( $DB_File::DB_Database::LOCKING );
|
28
|
|
|
|
|
|
|
}
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# print "true_close\n" if ($DB_File::DB_Database::DEBUG);
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# ###############################################################################
|
33
|
|
|
|
|
|
|
# Build the object in the memory, open the file
|
34
|
|
|
|
|
|
|
sub new {
|
35
|
|
|
|
|
|
|
__PACKAGE__->NullError();
|
36
|
|
|
|
|
|
|
my $class = shift;
|
37
|
|
|
|
|
|
|
my $new = bless {}, $class;
|
38
|
|
|
|
|
|
|
if (@_ and not $new->open(@_)) { return; }
|
39
|
|
|
|
|
|
|
return $new;
|
40
|
|
|
|
|
|
|
}
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# ###############################################################################
|
43
|
|
|
|
|
|
|
# Open the specified file.
|
44
|
|
|
|
|
|
|
sub open {
|
45
|
|
|
|
|
|
|
my ($self) = shift;
|
46
|
|
|
|
|
|
|
my %options;
|
47
|
|
|
|
|
|
|
if (scalar(@_) % 2) { $options{'name'} = shift; }
|
48
|
|
|
|
|
|
|
$self->{'DataBase'}->{'OpenOptions'} = { %options, @_ };
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
my %locoptions;
|
51
|
|
|
|
|
|
|
@locoptions{ qw( name readonly ) } = @{$self->{'DataBase'}->{'OpenOptions'}}{ qw( name readonly ) };
|
52
|
|
|
|
|
|
|
my $FileName = $locoptions{'name'};
|
53
|
|
|
|
|
|
|
for my $ext ('', '.db') {
|
54
|
|
|
|
|
|
|
if (-f $FileName.$ext) {
|
55
|
|
|
|
|
|
|
$locoptions{'name'} = $FileName.$ext;
|
56
|
|
|
|
|
|
|
$self->NullError();
|
57
|
|
|
|
|
|
|
return $self->real_open(%locoptions);
|
58
|
|
|
|
|
|
|
}
|
59
|
|
|
|
|
|
|
}
|
60
|
|
|
|
|
|
|
$locoptions{'name'} = $FileName;
|
61
|
|
|
|
|
|
|
return $self->real_open(%locoptions); # for nice error message
|
62
|
|
|
|
|
|
|
}
|
63
|
|
|
|
|
|
|
# ###############################################################################
|
64
|
|
|
|
|
|
|
# Close the file (and memo)
|
65
|
|
|
|
|
|
|
sub close {
|
66
|
|
|
|
|
|
|
my $self = shift;
|
67
|
|
|
|
|
|
|
$self->real_close;
|
68
|
|
|
|
|
|
|
$self->real_close_index( keys %{$self->{'Index'}} );
|
69
|
|
|
|
|
|
|
}
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
# ###############################################################################
|
72
|
|
|
|
|
|
|
# Creating new file
|
73
|
|
|
|
|
|
|
sub create {
|
74
|
|
|
|
|
|
|
__PACKAGE__->NullError();
|
75
|
|
|
|
|
|
|
my $class = shift;
|
76
|
|
|
|
|
|
|
my %options = @_;
|
77
|
|
|
|
|
|
|
if (ref $class) {
|
78
|
|
|
|
|
|
|
%options = ( %$class, %options ); $class = ref $class;
|
79
|
|
|
|
|
|
|
}
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
$options{'permits'}=0640 unless ( $options{'permits'} );
|
82
|
|
|
|
|
|
|
my $key;
|
83
|
|
|
|
|
|
|
for $key ( qw( name field_names ) ) {
|
84
|
|
|
|
|
|
|
if (not defined $options{$key}) {
|
85
|
|
|
|
|
|
|
__PACKAGE__->Error("Create Failed: Tag $key must be specified when creating new table\n");
|
86
|
|
|
|
|
|
|
return;
|
87
|
|
|
|
|
|
|
}
|
88
|
|
|
|
|
|
|
}
|
89
|
|
|
|
|
|
|
if (-f $options{'name'}) {
|
90
|
|
|
|
|
|
|
__PACKAGE__->Error("Taget File already exists\n");
|
91
|
|
|
|
|
|
|
return;
|
92
|
|
|
|
|
|
|
}
|
93
|
|
|
|
|
|
|
$options{'field_names'} = $class->check_field_names($options{'field_names'});
|
94
|
|
|
|
|
|
|
$options{'field_types'} = $class->check_field_types($options{'field_types'}, scalar(@{$options{'field_names'}}));
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
my $tmp = $class->new();
|
97
|
|
|
|
|
|
|
$tmp->real_create(%options) or return;
|
98
|
|
|
|
|
|
|
$tmp->close();
|
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
return $class->new($options{'name'});
|
101
|
|
|
|
|
|
|
}
|
102
|
|
|
|
|
|
|
# ###############################################################################
|
103
|
|
|
|
|
|
|
# check_field_names
|
104
|
|
|
|
|
|
|
sub check_field_names {
|
105
|
|
|
|
|
|
|
my ($self, $fields_name) = ( shift, shift );
|
106
|
|
|
|
|
|
|
my @fields_name = ref $fields_name ? @$fields_name : ();
|
107
|
|
|
|
|
|
|
my @return_fields_name;
|
108
|
|
|
|
|
|
|
my $i = 0;
|
109
|
|
|
|
|
|
|
my %fields_name;
|
110
|
|
|
|
|
|
|
while ( $i < scalar(@fields_name) ) {
|
111
|
|
|
|
|
|
|
$fields_name[$i] = uc $fields_name[$i];
|
112
|
|
|
|
|
|
|
# if the same field names appears
|
113
|
|
|
|
|
|
|
if (not $fields_name{ $fields_name[$i] } ) {
|
114
|
|
|
|
|
|
|
push ( @return_fields_name, $fields_name[$i] );
|
115
|
|
|
|
|
|
|
}
|
116
|
|
|
|
|
|
|
$fields_name{ $fields_name[$i] } = 1;
|
117
|
|
|
|
|
|
|
$i++;
|
118
|
|
|
|
|
|
|
}
|
119
|
|
|
|
|
|
|
return \@return_fields_name;
|
120
|
|
|
|
|
|
|
}
|
121
|
|
|
|
|
|
|
# ###############################################################################
|
122
|
|
|
|
|
|
|
# check_field_types
|
123
|
|
|
|
|
|
|
sub check_field_types {
|
124
|
|
|
|
|
|
|
my ($self, $fields_type) = ( shift, shift );
|
125
|
|
|
|
|
|
|
my @fields_type = ref $fields_type ? @$fields_type : ();
|
126
|
|
|
|
|
|
|
my $num = shift;
|
127
|
|
|
|
|
|
|
$num = scalar(@fields_type) if not defined $num;
|
128
|
|
|
|
|
|
|
my $i = 0;
|
129
|
|
|
|
|
|
|
while ( $i < $num ) {
|
130
|
|
|
|
|
|
|
$fields_type[$i] = uc substr($fields_type[$i],0,1);
|
131
|
|
|
|
|
|
|
# set default type
|
132
|
|
|
|
|
|
|
if ( $fields_type[$i] ne 'C' and $fields_type[$i] ne 'N') {
|
133
|
|
|
|
|
|
|
$fields_type[$i] = 'C';
|
134
|
|
|
|
|
|
|
}
|
135
|
|
|
|
|
|
|
$i++;
|
136
|
|
|
|
|
|
|
}
|
137
|
|
|
|
|
|
|
return \@fields_type;
|
138
|
|
|
|
|
|
|
}
|
139
|
|
|
|
|
|
|
# ###############################################################################
|
140
|
|
|
|
|
|
|
# check_field_names_hash
|
141
|
|
|
|
|
|
|
sub check_field_names_hash {
|
142
|
|
|
|
|
|
|
my $self = shift;
|
143
|
|
|
|
|
|
|
my @fields_name_hash = @_;
|
144
|
|
|
|
|
|
|
my $i = 0;
|
145
|
|
|
|
|
|
|
while ( $i < scalar(@fields_name_hash) ) {
|
146
|
|
|
|
|
|
|
$fields_name_hash[$i] = uc $fields_name_hash[$i];
|
147
|
|
|
|
|
|
|
$i+=2;
|
148
|
|
|
|
|
|
|
}
|
149
|
|
|
|
|
|
|
return @fields_name_hash;
|
150
|
|
|
|
|
|
|
}
|
151
|
|
|
|
|
|
|
# ###############################################################################
|
152
|
|
|
|
|
|
|
# Drop the table
|
153
|
|
|
|
|
|
|
sub drop {
|
154
|
|
|
|
|
|
|
my $self = shift;
|
155
|
|
|
|
|
|
|
$self->drop_index(keys %{$self->{'Index'}});
|
156
|
|
|
|
|
|
|
return $self->real_drop();
|
157
|
|
|
|
|
|
|
}
|
158
|
|
|
|
|
|
|
# ###############################################################################
|
159
|
|
|
|
|
|
|
# List of field names, types, lengths and decimals
|
160
|
|
|
|
|
|
|
sub field_names { @{shift->{'DataBase'}->{'data_field_names'}}; }
|
161
|
|
|
|
|
|
|
sub field_types { @{shift->{'DataBase'}->{'data_field_types'}}; }
|
162
|
|
|
|
|
|
|
sub field_name_to_num { my ($self, $name) = @_; $self->{'DataBase'}->{'data_field_names_hash'}->{uc $name}; }
|
163
|
|
|
|
|
|
|
sub rows { shift->{'DataBase'}->{'rows'}; }
|
164
|
|
|
|
|
|
|
sub select_hits { shift->{'Select'}->{'Result_Num'}; }
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# ###############################################################################
|
169
|
|
|
|
|
|
|
# Reading the records
|
170
|
|
|
|
|
|
|
# Returns fields of the specified record; optionally names of the required
|
171
|
|
|
|
|
|
|
# fields. If no names are specified, all fields are returned. Returns
|
172
|
|
|
|
|
|
|
# empty list on error.
|
173
|
|
|
|
|
|
|
sub get_record {
|
174
|
|
|
|
|
|
|
my ($self, $id) = (shift, shift);
|
175
|
|
|
|
|
|
|
return unless ( $id = $self->check_for_select($id) );
|
176
|
|
|
|
|
|
|
$self->get_record_nf( $id, map { $self->field_name_to_num($_); } @_ );
|
177
|
|
|
|
|
|
|
}
|
178
|
|
|
|
|
|
|
# ###############################################################################
|
179
|
|
|
|
|
|
|
sub get_record_hash {
|
180
|
|
|
|
|
|
|
my ($self, $id) = @_;
|
181
|
|
|
|
|
|
|
return unless ( $id = $self->check_for_select($id) );
|
182
|
|
|
|
|
|
|
my @data = $self->get_record_nf($id) or return;
|
183
|
|
|
|
|
|
|
my $hash = {};
|
184
|
|
|
|
|
|
|
@{$hash}{ ('__ID', $self->field_names) } = @data;
|
185
|
|
|
|
|
|
|
return %$hash if wantarray;
|
186
|
|
|
|
|
|
|
$hash;
|
187
|
|
|
|
|
|
|
}
|
188
|
|
|
|
|
|
|
# ###############################################################################
|
189
|
|
|
|
|
|
|
sub get_record_nf {
|
190
|
|
|
|
|
|
|
my ($self, $id, @fieldnums) = @_;
|
191
|
|
|
|
|
|
|
return unless ( $id = $self->check_for_select($id) );
|
192
|
|
|
|
|
|
|
my $data = $self->real_read_record($id) or return;
|
193
|
|
|
|
|
|
|
return ($id, @$data) if (not @fieldnums);
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
my @return_data = ($id);
|
196
|
|
|
|
|
|
|
foreach ( @fieldnums ) {
|
197
|
|
|
|
|
|
|
push (@return_data, @$data[$_] );
|
198
|
|
|
|
|
|
|
}
|
199
|
|
|
|
|
|
|
return @return_data;
|
200
|
|
|
|
|
|
|
}
|
201
|
|
|
|
|
|
|
# ###############################################################################
|
202
|
|
|
|
|
|
|
# Actually read the data
|
203
|
|
|
|
|
|
|
sub real_read_record {
|
204
|
|
|
|
|
|
|
my ($self, $id) = (shift, shift);
|
205
|
|
|
|
|
|
|
return if (not $self->{'DataBase'}->{'db'}->{$id} );
|
206
|
|
|
|
|
|
|
$self->csv_prase( $self->{'DataBase'}->{'db'}->{$id} );
|
207
|
|
|
|
|
|
|
}
|
208
|
|
|
|
|
|
|
# ###############################################################################
|
209
|
|
|
|
|
|
|
sub check_for_select {
|
210
|
|
|
|
|
|
|
my ($self, $id) = @_;
|
211
|
|
|
|
|
|
|
if ( not defined $id ) {
|
212
|
|
|
|
|
|
|
$id = shift ( @{$self->{'Select'}->{'Result'}} );
|
213
|
|
|
|
|
|
|
return undef if not defined $id;
|
214
|
|
|
|
|
|
|
}
|
215
|
|
|
|
|
|
|
$id;
|
216
|
|
|
|
|
|
|
}
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# ###############################################################################
|
223
|
|
|
|
|
|
|
# Write record, values of the fields are in the argument list.
|
224
|
|
|
|
|
|
|
sub set_record {
|
225
|
|
|
|
|
|
|
my ($self, $id, @data) = @_;
|
226
|
|
|
|
|
|
|
$self->real_write_record($id, @data);
|
227
|
|
|
|
|
|
|
}
|
228
|
|
|
|
|
|
|
# ###############################################################################
|
229
|
|
|
|
|
|
|
# Write record, fields are specified as hash, unspecified are set to undef/empty
|
230
|
|
|
|
|
|
|
sub set_record_hash {
|
231
|
|
|
|
|
|
|
my ($self, $id) = (shift,shift);
|
232
|
|
|
|
|
|
|
my %data = $self->check_field_names_hash(@_);
|
233
|
|
|
|
|
|
|
$self->set_record($id, map { $data{$_} } $self->field_names );
|
234
|
|
|
|
|
|
|
}
|
235
|
|
|
|
|
|
|
# ###############################################################################
|
236
|
|
|
|
|
|
|
# Write record, fields specified as hash, unspecified will be unchanged
|
237
|
|
|
|
|
|
|
sub update_record_hash {
|
238
|
|
|
|
|
|
|
my ($self, $id) = ( shift, shift );
|
239
|
|
|
|
|
|
|
my %olddata = $self->get_record_hash($id);
|
240
|
|
|
|
|
|
|
return unless %olddata;
|
241
|
|
|
|
|
|
|
$self->set_record_hash($id, %olddata, @_);
|
242
|
|
|
|
|
|
|
}
|
243
|
|
|
|
|
|
|
# ###############################################################################
|
244
|
|
|
|
|
|
|
# Write record, values of the fields are in the argument list.
|
245
|
|
|
|
|
|
|
sub append_record {
|
246
|
|
|
|
|
|
|
my ($self, @data) = @_;
|
247
|
|
|
|
|
|
|
$self->real_write_record(undef, @data);
|
248
|
|
|
|
|
|
|
}
|
249
|
|
|
|
|
|
|
# ###############################################################################
|
250
|
|
|
|
|
|
|
# Write record, fields are specified as hash, unspecified are set to undef/empty
|
251
|
|
|
|
|
|
|
sub append_record_hash {
|
252
|
|
|
|
|
|
|
my $self = shift;
|
253
|
|
|
|
|
|
|
my %data = $self->check_field_names_hash(@_);
|
254
|
|
|
|
|
|
|
$self->append_record( map { $data{$_} } $self->field_names );
|
255
|
|
|
|
|
|
|
}
|
256
|
|
|
|
|
|
|
# ###############################################################################
|
257
|
|
|
|
|
|
|
# Actually write the data (@newdata = undef means delete record)
|
258
|
|
|
|
|
|
|
sub real_write_record {
|
259
|
|
|
|
|
|
|
my ($self, $id) = (shift, shift);
|
260
|
|
|
|
|
|
|
$id = $self->{'DataBase'}->{'LastRecord'}+1 if (not defined $id);
|
261
|
|
|
|
|
|
|
my @newdata = @_;
|
262
|
|
|
|
|
|
|
my $olddata;
|
263
|
|
|
|
|
|
|
if ( $self->{'DataBase'}->{'rw'} ) {
|
264
|
|
|
|
|
|
|
$olddata = $self->real_read_record($id) if (defined $self->{'DataBase'}->{'db'}->{$id});
|
265
|
|
|
|
|
|
|
my ($tagname, $key);
|
266
|
|
|
|
|
|
|
my ($oldindex,$newindex);
|
267
|
|
|
|
|
|
|
while ( ($tagname,$key) = each (%{$self->{'Index'}}) ) {
|
268
|
|
|
|
|
|
|
#print "\nOldIndex: ";
|
269
|
|
|
|
|
|
|
$oldindex = $self->get_index_string($tagname, $olddata);
|
270
|
|
|
|
|
|
|
#print "\nNewIndex: ";
|
271
|
|
|
|
|
|
|
$newindex = $self->get_index_string($tagname, \@newdata);
|
272
|
|
|
|
|
|
|
# $DB_BTREE->{'compare'} = $self->get_compare_sub('index' => $tagname);
|
273
|
|
|
|
|
|
|
if ( not @newdata or $oldindex ne $newindex ) {
|
274
|
|
|
|
|
|
|
$self->real_delete_index_record( $tagname, $oldindex, $id ) if (defined $self->{'DataBase'}->{'db'}->{$id});
|
275
|
|
|
|
|
|
|
$self->real_insert_index_record( $tagname, $newindex, $id ) if ( @newdata );
|
276
|
|
|
|
|
|
|
}
|
277
|
|
|
|
|
|
|
}
|
278
|
|
|
|
|
|
|
if ( scalar(@newdata) ) {
|
279
|
|
|
|
|
|
|
$self->{'DataBase'}->{'db'}->{$id} = $self->csv_combine(@newdata);
|
280
|
|
|
|
|
|
|
$self->{'DataBase'}->{'db'}->{'__Total_Records'} ++;
|
281
|
|
|
|
|
|
|
if( int($id) > $self->{'DataBase'}->{'LastRecord'} ) {
|
282
|
|
|
|
|
|
|
$self->{'DataBase'}->{'db'}->{'__Last_Record'} = int($id);
|
283
|
|
|
|
|
|
|
$self->{'DataBase'}->{'LastRecord'} = int($id);
|
284
|
|
|
|
|
|
|
}
|
285
|
|
|
|
|
|
|
}else {
|
286
|
|
|
|
|
|
|
return if (not defined $self->{'DataBase'}->{'db'}->{$id});
|
287
|
|
|
|
|
|
|
delete $self->{'DataBase'}->{'db'}->{$id};
|
288
|
|
|
|
|
|
|
$self->{'DataBase'}->{'db'}->{'__Total_Records'} --;
|
289
|
|
|
|
|
|
|
}
|
290
|
|
|
|
|
|
|
}else {
|
291
|
|
|
|
|
|
|
$self->Error("Writing Record Failed: File is opened only for reading.\n");
|
292
|
|
|
|
|
|
|
return;
|
293
|
|
|
|
|
|
|
}
|
294
|
|
|
|
|
|
|
$id;
|
295
|
|
|
|
|
|
|
}
|
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
# ###############################################################################
|
298
|
|
|
|
|
|
|
# Delete record
|
299
|
|
|
|
|
|
|
sub delete_record {
|
300
|
|
|
|
|
|
|
my ($self, @id) = @_;
|
301
|
|
|
|
|
|
|
my $id;
|
302
|
|
|
|
|
|
|
my $num = 0;
|
303
|
|
|
|
|
|
|
foreach $id (@id) {
|
304
|
|
|
|
|
|
|
$num++ if ( $self->real_write_record( $id ) );
|
305
|
|
|
|
|
|
|
}
|
306
|
|
|
|
|
|
|
$num;
|
307
|
|
|
|
|
|
|
}
|
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub get_hashref { shift->{'db'} }
|
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# ###############################################################################
|
322
|
|
|
|
|
|
|
# Open the specified file.
|
323
|
|
|
|
|
|
|
sub real_create {
|
324
|
|
|
|
|
|
|
print "true_create\n" if ($DB_File::DB_Database::DEBUG);
|
325
|
|
|
|
|
|
|
my $self = shift;
|
326
|
|
|
|
|
|
|
my %options = @_;
|
327
|
|
|
|
|
|
|
if (defined $self->{'DataBase'}->{'db'}) { $self->close(); }
|
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
my %db;
|
330
|
|
|
|
|
|
|
if( tie %db, "DB_File", $options{'name'}, O_CREAT|O_RDWR, $options{'permits'}, $DB_HASH) {
|
331
|
|
|
|
|
|
|
$db{'__Version'} = $VERSION;
|
332
|
|
|
|
|
|
|
$db{'__Last_Record'} = 0;
|
333
|
|
|
|
|
|
|
$db{'__Total_Records'} = 0;
|
334
|
|
|
|
|
|
|
$db{'__Field_names'} = $self->csv_combine(@{$options{'field_names'}});
|
335
|
|
|
|
|
|
|
$db{'__Field_types'} = $self->csv_combine(@{$options{'field_types'}});
|
336
|
|
|
|
|
|
|
}else{
|
337
|
|
|
|
|
|
|
$self->Error("Error opening file $options{'name'}: $!\n");
|
338
|
|
|
|
|
|
|
return;
|
339
|
|
|
|
|
|
|
}
|
340
|
|
|
|
|
|
|
1; # success
|
341
|
|
|
|
|
|
|
}
|
342
|
|
|
|
|
|
|
# ###############################################################################
|
343
|
|
|
|
|
|
|
# Drop (unlink) the file
|
344
|
|
|
|
|
|
|
sub real_drop {
|
345
|
|
|
|
|
|
|
my $self = shift;
|
346
|
|
|
|
|
|
|
$self->NullError();
|
347
|
|
|
|
|
|
|
if (defined $self->{'DataBase'}->{'FileName'}) {
|
348
|
|
|
|
|
|
|
my $FileName = $self->{'DataBase'}->{'FileName'};
|
349
|
|
|
|
|
|
|
$self->close() if defined $self->{'DataBase'}->{'db'};
|
350
|
|
|
|
|
|
|
if (not unlink $FileName)
|
351
|
|
|
|
|
|
|
{ $self->Error("Error unlinking file $FileName: $!\n"); return; };
|
352
|
|
|
|
|
|
|
}
|
353
|
|
|
|
|
|
|
1;
|
354
|
|
|
|
|
|
|
}
|
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# ###############################################################################
|
357
|
|
|
|
|
|
|
# Open the specified file.
|
358
|
|
|
|
|
|
|
sub real_open {
|
359
|
|
|
|
|
|
|
my $self = shift;
|
360
|
|
|
|
|
|
|
my %options = @_;
|
361
|
|
|
|
|
|
|
if (defined $self->{'DataBase'}->{'db'}
|
362
|
|
|
|
|
|
|
and ( $self->{'DataBase'}->{'FileName'} ne $options{'name'}
|
363
|
|
|
|
|
|
|
or $self->{'DataBase'}->{'rw'} eq $options{'readonly'} )) { $self->close(); }
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
my %db;
|
366
|
|
|
|
|
|
|
my $fh;
|
367
|
|
|
|
|
|
|
my $rw = 0;
|
368
|
|
|
|
|
|
|
my $ok = 0;
|
369
|
|
|
|
|
|
|
my $lock = 0;
|
370
|
|
|
|
|
|
|
if (not $options{'readonly'}) {
|
371
|
|
|
|
|
|
|
if( $fh = tie %db, "DB_File", $options{'name'}, O_RDWR, 0640, $DB_HASH) {
|
372
|
|
|
|
|
|
|
$rw = 1; $ok = 1;
|
373
|
|
|
|
|
|
|
}
|
374
|
|
|
|
|
|
|
}else {
|
375
|
|
|
|
|
|
|
if( $fh = tie %db, "DB_File", $options{'name'}, O_RDONLY, 0640, $DB_HASH) {
|
376
|
|
|
|
|
|
|
$rw = 0; $ok = 1;
|
377
|
|
|
|
|
|
|
}
|
378
|
|
|
|
|
|
|
}
|
379
|
|
|
|
|
|
|
if (not $ok) {
|
380
|
|
|
|
|
|
|
$self->Error("Error opening file $options{'name'}: $!\n");
|
381
|
|
|
|
|
|
|
return;
|
382
|
|
|
|
|
|
|
}
|
383
|
|
|
|
|
|
|
@{$self->{'DataBase'}}{ qw( fh db FileName rw ) } = ($fh, \%db, $options{'name'}, $rw);
|
384
|
|
|
|
|
|
|
$self->{'DataBase'}->{'lockfh'} = $self->database_lock ( 'FileName' => $self->{'DataBase'}->{'FileName'} ,
|
385
|
|
|
|
|
|
|
'rw' => $self->{'DataBase'}->{'rw'} ,
|
386
|
|
|
|
|
|
|
'permits' => 0640 );
|
387
|
|
|
|
|
|
|
$self->read_head;
|
388
|
|
|
|
|
|
|
$self->real_open_index;
|
389
|
|
|
|
|
|
|
}
|
390
|
|
|
|
|
|
|
# ###############################################################################
|
391
|
|
|
|
|
|
|
# Open the specified file.
|
392
|
|
|
|
|
|
|
sub real_open_index {
|
393
|
|
|
|
|
|
|
print "open_index\n" if ($DB_File::DB_Database::DEBUG);
|
394
|
|
|
|
|
|
|
my $self = shift;
|
395
|
|
|
|
|
|
|
my ($tag_name,$tag_info);
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
while ( ($tag_name,$tag_info) = each( %{$self->{'Index'}}) ) {
|
398
|
|
|
|
|
|
|
my $recreate = 0;
|
399
|
|
|
|
|
|
|
if (not -f $tag_info->{'FileName'}) {
|
400
|
|
|
|
|
|
|
$self->Error("Warning: Can't find Index file ".$tag_info->{'FileName'}." , ReCreated it.\n");
|
401
|
|
|
|
|
|
|
$recreate = 1;
|
402
|
|
|
|
|
|
|
$self->real_create_index('tag' => $tag_name ,
|
403
|
|
|
|
|
|
|
'FileName' => $tag_info->{'FileName'} ,
|
404
|
|
|
|
|
|
|
'key' => $tag_info->{'key'} ,
|
405
|
|
|
|
|
|
|
'compare' => $self->get_compare_sub('index' => $tag_name),
|
406
|
|
|
|
|
|
|
'permits' => 0640 );
|
407
|
|
|
|
|
|
|
}
|
408
|
|
|
|
|
|
|
my %db;
|
409
|
|
|
|
|
|
|
my $fh;
|
410
|
|
|
|
|
|
|
my $rw = 0;
|
411
|
|
|
|
|
|
|
my $ok = 0;
|
412
|
|
|
|
|
|
|
my $lock = 0;
|
413
|
|
|
|
|
|
|
$DB_BTREE->{'flags'} = R_DUP;
|
414
|
|
|
|
|
|
|
$DB_BTREE->{'compare'} = $self->get_compare_sub('index' => $tag_name);
|
415
|
|
|
|
|
|
|
if ( $self->{'DataBase'}->{'rw'} ) {
|
416
|
|
|
|
|
|
|
if( $fh = tie %db, "DB_File", $tag_info->{'FileName'}, O_RDWR, 0640, $DB_BTREE) {
|
417
|
|
|
|
|
|
|
$rw = 1; $ok = 1;
|
418
|
|
|
|
|
|
|
}
|
419
|
|
|
|
|
|
|
}else {
|
420
|
|
|
|
|
|
|
if( $fh = tie %db, "DB_File", $tag_info->{'FileName'}, O_RDONLY, 0640, $DB_BTREE) {
|
421
|
|
|
|
|
|
|
$rw = 0; $ok = 1;
|
422
|
|
|
|
|
|
|
}
|
423
|
|
|
|
|
|
|
}
|
424
|
|
|
|
|
|
|
if (not $ok) {
|
425
|
|
|
|
|
|
|
$self->Error("Error opening Index file ".$tag_info->{'FileName'}.": $!\n");
|
426
|
|
|
|
|
|
|
return;
|
427
|
|
|
|
|
|
|
}
|
428
|
|
|
|
|
|
|
@{$tag_info}{ qw( fh db rw ) } = ($fh, \%db, $rw);
|
429
|
|
|
|
|
|
|
$tag_info->{'lockfh'} = $self->database_lock ( 'FileName' => $tag_info->{'FileName'} ,
|
430
|
|
|
|
|
|
|
'rw' => $self->{'DataBase'}->{'rw'} ,
|
431
|
|
|
|
|
|
|
'permits' => 0640 );
|
432
|
|
|
|
|
|
|
$self->recreate_index( $tag_name ) if $recreate;
|
433
|
|
|
|
|
|
|
}
|
434
|
|
|
|
|
|
|
1;
|
435
|
|
|
|
|
|
|
}
|
436
|
|
|
|
|
|
|
# ###############################################################################
|
437
|
|
|
|
|
|
|
# Open the specified file.
|
438
|
|
|
|
|
|
|
sub read_head {
|
439
|
|
|
|
|
|
|
my $self = shift;
|
440
|
|
|
|
|
|
|
if (not defined $self->{'DataBase'}->{'db'}) { $self->close();return; }
|
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
my $db = $self->{'DataBase'}->{'db'};
|
443
|
|
|
|
|
|
|
my ( $data_version, $rows, $data_structure_raw, $data_fieldtype_raw, $index_raw, $index_keyfield_raw)
|
444
|
|
|
|
|
|
|
= ($db->{'__Version'}, $db->{'__Total_Records'}, $db->{'__Field_names'}, $db->{'__Field_types'}, $db->{'__Index'}, $db->{'__IndexKeyField'});
|
445
|
|
|
|
|
|
|
if (not ($data_version and $data_structure_raw) ) {
|
446
|
|
|
|
|
|
|
$self->close();
|
447
|
|
|
|
|
|
|
$self->Error("DATA Version Error: This file is not normally created by DB_File::DB_Database.\n"); return;
|
448
|
|
|
|
|
|
|
return;
|
449
|
|
|
|
|
|
|
}
|
450
|
|
|
|
|
|
|
my $data_structure = $self->csv_prase($data_structure_raw);
|
451
|
|
|
|
|
|
|
my $data_fieldtype = $self->csv_prase($data_fieldtype_raw);
|
452
|
|
|
|
|
|
|
# set fields no to hash
|
453
|
|
|
|
|
|
|
my %data_structure_hash;
|
454
|
|
|
|
|
|
|
foreach (0 .. scalar(@$data_structure)-1) {
|
455
|
|
|
|
|
|
|
$data_structure_hash{ @$data_structure[$_] } = $_;
|
456
|
|
|
|
|
|
|
}
|
457
|
|
|
|
|
|
|
@{$self->{'DataBase'}}{ qw( data_version rows data_field_names data_field_types data_field_names_hash LastRecord ) }
|
458
|
|
|
|
|
|
|
= ($data_version, $rows, $data_structure, $data_fieldtype, \%data_structure_hash, $db->{'__Last_Record'} );
|
459
|
|
|
|
|
|
|
# set index tags
|
460
|
|
|
|
|
|
|
my $index_tag = $self->csv_prase($index_raw);
|
461
|
|
|
|
|
|
|
my $index_keyfield = $self->csv_prase($index_keyfield_raw);
|
462
|
|
|
|
|
|
|
foreach (0 .. scalar(@$index_tag)-1) {
|
463
|
|
|
|
|
|
|
$self->{'Index'}->{ @$index_tag[$_] } = { 'FileName' => $self->{'DataBase'}->{'FileName'}.'_'.@$index_tag[$_] ,
|
464
|
|
|
|
|
|
|
'KeyField' => @$index_keyfield[$_] ,
|
465
|
|
|
|
|
|
|
'KeyField_type'=> ($self->field_types)[ $self->field_name_to_num(@$index_keyfield[$_]) ] };
|
466
|
|
|
|
|
|
|
}
|
467
|
|
|
|
|
|
|
1;
|
468
|
|
|
|
|
|
|
}
|
469
|
|
|
|
|
|
|
# ###############################################################################
|
470
|
|
|
|
|
|
|
# Close the file
|
471
|
|
|
|
|
|
|
sub real_close {
|
472
|
|
|
|
|
|
|
print "real_close\n" if ($DB_File::DB_Database::DEBUG);
|
473
|
|
|
|
|
|
|
my $self = shift;
|
474
|
|
|
|
|
|
|
$self->database_unlock( 'lockfh' => $self->{'DataBase'}->{'lockfh'} );
|
475
|
|
|
|
|
|
|
undef $self->{'DataBase'}->{'fh'};
|
476
|
|
|
|
|
|
|
untie %{$self->{'DataBase'}->{'db'}};
|
477
|
|
|
|
|
|
|
delete $self->{'DataBase'};
|
478
|
|
|
|
|
|
|
}
|
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
# ###############################################################################
|
481
|
|
|
|
|
|
|
sub errstr {
|
482
|
|
|
|
|
|
|
my $self = shift;
|
483
|
|
|
|
|
|
|
return ( ref $self ? $self->{'errstr'} : $DB_File::DB_Database::errstr );
|
484
|
|
|
|
|
|
|
}
|
485
|
|
|
|
|
|
|
# ###############################################################################
|
486
|
|
|
|
|
|
|
# Set errstr if there is debug level
|
487
|
|
|
|
|
|
|
sub Error {
|
488
|
|
|
|
|
|
|
my $self = shift;
|
489
|
|
|
|
|
|
|
( ref $self ? $self->{'errstr'} : $DB_File::DB_Database::errstr ) .= join '', @_;
|
490
|
|
|
|
|
|
|
# print @_ if ($DB_File::DB_Database::DEBUG);
|
491
|
|
|
|
|
|
|
}
|
492
|
|
|
|
|
|
|
# ###############################################################################
|
493
|
|
|
|
|
|
|
# Null the errstr
|
494
|
|
|
|
|
|
|
sub NullError
|
495
|
|
|
|
|
|
|
{ shift->Error(''); }
|
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
# ###############################################################################
|
500
|
|
|
|
|
|
|
# Dump
|
501
|
|
|
|
|
|
|
sub dump_all {
|
502
|
|
|
|
|
|
|
my $self = shift;
|
503
|
|
|
|
|
|
|
use Data::Dumper; $Data::Dumper::Indent=1;
|
504
|
|
|
|
|
|
|
print &Data::Dumper::Dumper($self);
|
505
|
|
|
|
|
|
|
1; # return true since everything went fine
|
506
|
|
|
|
|
|
|
}
|
507
|
|
|
|
|
|
|
# ###############################################################################
|
508
|
|
|
|
|
|
|
# Dump
|
509
|
|
|
|
|
|
|
sub dump_data {
|
510
|
|
|
|
|
|
|
my $self = shift;
|
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
my $i = 0;
|
513
|
|
|
|
|
|
|
my @field_names = $self->field_names;
|
514
|
|
|
|
|
|
|
my @field_types = $self->field_types;
|
515
|
|
|
|
|
|
|
print "\n";
|
516
|
|
|
|
|
|
|
print "Data File Name: ".$self->{'DataBase'}->{'FileName'}." \n";
|
517
|
|
|
|
|
|
|
print " DataVersion : ".$self->{'DataBase'}->{'data_version'}."\n";
|
518
|
|
|
|
|
|
|
print " Privility : Read ".($self->{'DataBase'}->{'rw'} ? "and Write" : "Only")."\n";
|
519
|
|
|
|
|
|
|
print " Locking : ".($self->{'DataBase'}->{'lockfh'} ? "" : "Not ")."Locked\n";
|
520
|
|
|
|
|
|
|
print " ID -> "."@field_names "."\n";
|
521
|
|
|
|
|
|
|
print " "."@field_types "."\n";
|
522
|
|
|
|
|
|
|
print " Table Data :\n";
|
523
|
|
|
|
|
|
|
my ($key, $content_raw, $content, $status);
|
524
|
|
|
|
|
|
|
while ( ($key, $content_raw) = each( %{$self->{'DataBase'}->{'db'}} ) ) {
|
525
|
|
|
|
|
|
|
if (not $key =~ /^__/ ) {
|
526
|
|
|
|
|
|
|
$content = $self->csv_prase($content_raw);
|
527
|
|
|
|
|
|
|
print " $key -> "."@$content "."\n";
|
528
|
|
|
|
|
|
|
$i++;
|
529
|
|
|
|
|
|
|
}
|
530
|
|
|
|
|
|
|
}
|
531
|
|
|
|
|
|
|
print " Totally : $i Recrods\n";
|
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
my $x;
|
534
|
|
|
|
|
|
|
foreach $_ ( keys %{$self->{'Index'}} ) {
|
535
|
|
|
|
|
|
|
print "\n";
|
536
|
|
|
|
|
|
|
print "Index $_\n";
|
537
|
|
|
|
|
|
|
print " Index File Name: ".$self->{'Index'}->{$_}->{'FileName'}."\n";
|
538
|
|
|
|
|
|
|
print " Privility : Read ".($self->{'Index'}->{$_}->{'rw'} ? "and Write" : "Only")."\n";
|
539
|
|
|
|
|
|
|
print " Locking : ".($self->{'Index'}->{$_}->{'lockfh'} ? "" : "Not ")."Locked\n";
|
540
|
|
|
|
|
|
|
print " KeyField : ".$self->{'Index'}->{$_}->{'KeyField'}."\n";
|
541
|
|
|
|
|
|
|
print " Index Content :\n";
|
542
|
|
|
|
|
|
|
$i = 0;
|
543
|
|
|
|
|
|
|
$x = $self->{'Index'}->{ $_ }->{'fh'};
|
544
|
|
|
|
|
|
|
$key = $content = 0;
|
545
|
|
|
|
|
|
|
for ($status = $x->seq($key, $content, R_FIRST) ; $status == 0 ; $status = $x->seq($key, $content, R_NEXT) ) {
|
546
|
|
|
|
|
|
|
print " $key -> $content\n";
|
547
|
|
|
|
|
|
|
$i++;
|
548
|
|
|
|
|
|
|
}
|
549
|
|
|
|
|
|
|
print " Totally : $i Recrods\n";
|
550
|
|
|
|
|
|
|
}
|
551
|
|
|
|
|
|
|
1; # return true since everything went fine
|
552
|
|
|
|
|
|
|
}
|
553
|
|
|
|
|
|
|
# ###############################################################################
|
554
|
|
|
|
|
|
|
# Dump
|
555
|
|
|
|
|
|
|
sub dump {
|
556
|
|
|
|
|
|
|
my $self = shift;
|
557
|
|
|
|
|
|
|
use Data::Dumper; $Data::Dumper::Indent=1;
|
558
|
|
|
|
|
|
|
print &Data::Dumper::Dumper(shift);
|
559
|
|
|
|
|
|
|
1; # return true since everything went fine
|
560
|
|
|
|
|
|
|
}
|
561
|
|
|
|
|
|
|
# ###############################################################################
|
562
|
|
|
|
|
|
|
# CSV string to columns
|
563
|
|
|
|
|
|
|
sub csv_prase {
|
564
|
|
|
|
|
|
|
my $self = shift;
|
565
|
|
|
|
|
|
|
my $string = shift;
|
566
|
|
|
|
|
|
|
my $result = [];
|
567
|
|
|
|
|
|
|
return $result unless ( $string );
|
568
|
|
|
|
|
|
|
$string=','.$string.',';
|
569
|
|
|
|
|
|
|
@$result =($string=~ /,("(?:[^"]|(?:[^"]*?""))*?"|[^"]*?)(?=,)/mg);
|
570
|
|
|
|
|
|
|
foreach(0..scalar(@$result)-1) {
|
571
|
|
|
|
|
|
|
$result->[$_]=~ s/\A"|"\Z//g;
|
572
|
|
|
|
|
|
|
$result->[$_]=~ s/""/"/g;
|
573
|
|
|
|
|
|
|
}
|
574
|
|
|
|
|
|
|
return $result;
|
575
|
|
|
|
|
|
|
}
|
576
|
|
|
|
|
|
|
# ###############################################################################
|
577
|
|
|
|
|
|
|
# columns to CSV string
|
578
|
|
|
|
|
|
|
sub csv_combine {
|
579
|
|
|
|
|
|
|
my $self = shift;
|
580
|
|
|
|
|
|
|
my @content = @_;
|
581
|
|
|
|
|
|
|
foreach (0..scalar(@content)-1) {
|
582
|
|
|
|
|
|
|
$content[$_]=~ s/"/""/g;
|
583
|
|
|
|
|
|
|
$content[$_]="\"$content[$_]\"" if($content[$_]);
|
584
|
|
|
|
|
|
|
}
|
585
|
|
|
|
|
|
|
return join(',',@content);
|
586
|
|
|
|
|
|
|
}
|
587
|
|
|
|
|
|
|
# ###############################################################################
|
588
|
|
|
|
|
|
|
# Lcok
|
589
|
|
|
|
|
|
|
sub database_lock {
|
590
|
|
|
|
|
|
|
my $self = shift;
|
591
|
|
|
|
|
|
|
my %options = @_;
|
592
|
|
|
|
|
|
|
my $lock = 0;
|
593
|
|
|
|
|
|
|
my $lockfile = $options{'FileName'}.'.lock';
|
594
|
|
|
|
|
|
|
if ( $DB_File::DB_Database::LOCKING ) {
|
595
|
|
|
|
|
|
|
my $fh = new IO::File;
|
596
|
|
|
|
|
|
|
if ( not $fh->open($lockfile, O_CREAT|O_RDWR, $options{'permits'}) ) {
|
597
|
|
|
|
|
|
|
$self->Error("Error occur when making lock file $lockfile: $!.\n");
|
598
|
|
|
|
|
|
|
return;
|
599
|
|
|
|
|
|
|
}
|
600
|
|
|
|
|
|
|
if ( $options{'rw'} ) {
|
601
|
|
|
|
|
|
|
if ( $self->_lockex($fh) ) {
|
602
|
|
|
|
|
|
|
print "lockex_success\n" if ($DB_File::DB_Database::DEBUG);
|
603
|
|
|
|
|
|
|
$lock = 1;
|
604
|
|
|
|
|
|
|
}else {
|
605
|
|
|
|
|
|
|
$self->Error("Error occur when locking (for read & write) the lock file: $!.\n");
|
606
|
|
|
|
|
|
|
return;
|
607
|
|
|
|
|
|
|
}
|
608
|
|
|
|
|
|
|
}else {
|
609
|
|
|
|
|
|
|
if ( $self->_locksh($fh) ) {
|
610
|
|
|
|
|
|
|
print "locksh_success\n" if ($DB_File::DB_Database::DEBUG);
|
611
|
|
|
|
|
|
|
$lock = 1;
|
612
|
|
|
|
|
|
|
}else {
|
613
|
|
|
|
|
|
|
$self->Error("Error occur when locking (for read) the lock file: $!.\n");
|
614
|
|
|
|
|
|
|
return;
|
615
|
|
|
|
|
|
|
}
|
616
|
|
|
|
|
|
|
}
|
617
|
|
|
|
|
|
|
return $fh;
|
618
|
|
|
|
|
|
|
}
|
619
|
|
|
|
|
|
|
return;
|
620
|
|
|
|
|
|
|
}
|
621
|
|
|
|
|
|
|
# ###############################################################################
|
622
|
|
|
|
|
|
|
# Unlcok
|
623
|
|
|
|
|
|
|
sub database_unlock {
|
624
|
|
|
|
|
|
|
my $self = shift;
|
625
|
|
|
|
|
|
|
my %options = @_;
|
626
|
|
|
|
|
|
|
my $lockfh = $options{'lockfh'};
|
627
|
|
|
|
|
|
|
if ( $lockfh ) {
|
628
|
|
|
|
|
|
|
if ( $self->_unlock($lockfh) ) {
|
629
|
|
|
|
|
|
|
print "unlock_success\n" if ($DB_File::DB_Database::DEBUG);
|
630
|
|
|
|
|
|
|
$lockfh->close;
|
631
|
|
|
|
|
|
|
}else {
|
632
|
|
|
|
|
|
|
$self->Error("Error occur when unlocking the lock file: $!.\n");
|
633
|
|
|
|
|
|
|
return;
|
634
|
|
|
|
|
|
|
}
|
635
|
|
|
|
|
|
|
}
|
636
|
|
|
|
|
|
|
1;
|
637
|
|
|
|
|
|
|
}
|
638
|
|
|
|
|
|
|
#
|
639
|
|
|
|
|
|
|
#sub _locksh { flock(shift, LOCK_SH); }
|
640
|
|
|
|
|
|
|
#sub _lockex { flock(shift, LOCK_EX); }
|
641
|
|
|
|
|
|
|
#sub _unlock { flock(shift, LOCK_UN); }
|
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
sub _locksh { 1; }
|
644
|
|
|
|
|
|
|
sub _lockex { 1; }
|
645
|
|
|
|
|
|
|
sub _unlock { 1; }
|
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
# ###############################################################################
|
652
|
|
|
|
|
|
|
# Compare sub maker
|
653
|
|
|
|
|
|
|
sub get_compare_sub {
|
654
|
|
|
|
|
|
|
my $self = shift;
|
655
|
|
|
|
|
|
|
my %options = @_;
|
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
my $compare_sub;
|
658
|
|
|
|
|
|
|
if ( defined $options{'index'} ) {
|
659
|
|
|
|
|
|
|
$options{'key'} = $self->{'Index'}->{ $options{'index'} }->{'KeyField'};
|
660
|
|
|
|
|
|
|
}
|
661
|
|
|
|
|
|
|
if( defined $options{'type'} ) {
|
662
|
|
|
|
|
|
|
if ( $options{'type'} eq 'N' ) {
|
663
|
|
|
|
|
|
|
$compare_sub = sub {
|
664
|
|
|
|
|
|
|
$_[0] <=> $_[1];
|
665
|
|
|
|
|
|
|
}
|
666
|
|
|
|
|
|
|
}else {
|
667
|
|
|
|
|
|
|
$compare_sub = sub {
|
668
|
|
|
|
|
|
|
$_[0] cmp $_[1];
|
669
|
|
|
|
|
|
|
}
|
670
|
|
|
|
|
|
|
}
|
671
|
|
|
|
|
|
|
}elsif( defined $options{'key'} ) { # eg. key => 'ID(10)+-Age(2)'
|
672
|
|
|
|
|
|
|
my @key = split(/\+/,$options{'key'});
|
673
|
|
|
|
|
|
|
my ($key, $type, $length, $reverse);
|
674
|
|
|
|
|
|
|
my $position = 0;
|
675
|
|
|
|
|
|
|
my $code = "\$compare_sub = sub {\n";
|
676
|
|
|
|
|
|
|
foreach $key (@key) {
|
677
|
|
|
|
|
|
|
($key, $length) = split(/\(/,$key);
|
678
|
|
|
|
|
|
|
$reverse = ($key =~ s/^-//g);
|
679
|
|
|
|
|
|
|
($length) = split(/\)/,$length);
|
680
|
|
|
|
|
|
|
if (defined $length) { $length = ",$length"; }
|
681
|
|
|
|
|
|
|
$type = $self->{'DataBase'}->{'data_field_types'}->[ $self->field_name_to_num($key) ];
|
682
|
|
|
|
|
|
|
# print ($key, $type, $length, $reverse);
|
683
|
|
|
|
|
|
|
if ($reverse) { $code .= "substr(\$_[1],$position$length)"; }
|
684
|
|
|
|
|
|
|
else { $code .= "substr(\$_[0],$position$length)"; }
|
685
|
|
|
|
|
|
|
if ($type eq 'N' ) { $code .= ' <=> '; }
|
686
|
|
|
|
|
|
|
else { $code .= ' cmp '; }
|
687
|
|
|
|
|
|
|
if ($reverse) { $code .= "substr(\$_[0],$position$length)"; }
|
688
|
|
|
|
|
|
|
else { $code .= "substr(\$_[1],$position$length)"; }
|
689
|
|
|
|
|
|
|
$code .= "\n or \n";
|
690
|
|
|
|
|
|
|
$position += $length;
|
691
|
|
|
|
|
|
|
}
|
692
|
|
|
|
|
|
|
$code .= " 0\;\n}\;";
|
693
|
|
|
|
|
|
|
eval($code);
|
694
|
|
|
|
|
|
|
}
|
695
|
|
|
|
|
|
|
$compare_sub;
|
696
|
|
|
|
|
|
|
}
|
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
# ###############################################################################
|
699
|
|
|
|
|
|
|
# make index keywords
|
700
|
|
|
|
|
|
|
sub get_index_string {
|
701
|
|
|
|
|
|
|
my $self = shift;
|
702
|
|
|
|
|
|
|
my ($tag_name, $dataref) = @_;
|
703
|
|
|
|
|
|
|
return if(not defined $self->{'Index'}->{ $tag_name } );
|
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
my @key = split(/\+/,$self->{'Index'}->{ $tag_name }->{'KeyField'});
|
706
|
|
|
|
|
|
|
my ($key, $length, $reverse);
|
707
|
|
|
|
|
|
|
my $result;
|
708
|
|
|
|
|
|
|
foreach $key (@key) {
|
709
|
|
|
|
|
|
|
($key, $length) = split(/\(/,$key);
|
710
|
|
|
|
|
|
|
$reverse = ($key =~ s/^-//g);
|
711
|
|
|
|
|
|
|
($length) = split(/\)/,$length);
|
712
|
|
|
|
|
|
|
$length = int $length;
|
713
|
|
|
|
|
|
|
if ($length) {
|
714
|
|
|
|
|
|
|
$result .= sprintf("%${length}s", $dataref->[ $self->field_name_to_num($key) ]);
|
715
|
|
|
|
|
|
|
}else {
|
716
|
|
|
|
|
|
|
$result .= $dataref->[ $self->field_name_to_num($key) ];
|
717
|
|
|
|
|
|
|
}
|
718
|
|
|
|
|
|
|
}
|
719
|
|
|
|
|
|
|
return $result;
|
720
|
|
|
|
|
|
|
}
|
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
# ###############################################################################
|
723
|
|
|
|
|
|
|
# Creating new index
|
724
|
|
|
|
|
|
|
sub create_index {
|
725
|
|
|
|
|
|
|
my $self = shift;
|
726
|
|
|
|
|
|
|
my %options = @_;
|
727
|
|
|
|
|
|
|
return unless (defined $self->{'DataBase'}->{'db'} and $self->{'DataBase'}->{'rw'});
|
728
|
|
|
|
|
|
|
return unless (defined $options{'name'} and defined $options{'key'});
|
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
my $tag_name = uc $options{'name'};
|
731
|
|
|
|
|
|
|
$options{'permits'} = 0640 unless ( $options{'permits'} );
|
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
my %createoptions = ( 'tag' => $tag_name ,
|
734
|
|
|
|
|
|
|
'FileName' => $self->{'DataBase'}->{'FileName'}.'_'.$tag_name ,
|
735
|
|
|
|
|
|
|
'key' => uc $options{'key'} ,
|
736
|
|
|
|
|
|
|
'compare' => $self->get_compare_sub('key' => uc $options{'key'}), # 'type' => $self->{'DataBase'}->{'data_field_types'}->[ $self->field_name_to_num($options{'key'}) ]
|
737
|
|
|
|
|
|
|
'permits' => $options{'permits'} );
|
738
|
|
|
|
|
|
|
if (-f $createoptions{'FileName'} or defined $self->{'Index'}->{$tag_name}) {
|
739
|
|
|
|
|
|
|
$self->Error("Taget Index File '$createoptions{'FileName'}' already exists.\n");
|
740
|
|
|
|
|
|
|
return;
|
741
|
|
|
|
|
|
|
}
|
742
|
|
|
|
|
|
|
$self->real_create_index(%createoptions) or return;
|
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
my @index_tags;
|
745
|
|
|
|
|
|
|
my @index_keyfields;
|
746
|
|
|
|
|
|
|
my ($other_tag_name,$key);
|
747
|
|
|
|
|
|
|
while ( ($other_tag_name,$key) = each (%{$self->{'Index'}}) ) {
|
748
|
|
|
|
|
|
|
push (@index_tags, $other_tag_name);
|
749
|
|
|
|
|
|
|
push (@index_keyfields, $key->{'KeyField'});
|
750
|
|
|
|
|
|
|
}
|
751
|
|
|
|
|
|
|
push (@index_tags, $tag_name);
|
752
|
|
|
|
|
|
|
push (@index_keyfields, $createoptions{'key'});
|
753
|
|
|
|
|
|
|
$self->{'DataBase'}->{'db'}->{'__Index'} = $self->csv_combine(@index_tags);
|
754
|
|
|
|
|
|
|
$self->{'DataBase'}->{'db'}->{'__IndexKeyField'} = $self->csv_combine(@index_keyfields);
|
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
$self->close();
|
757
|
|
|
|
|
|
|
$self->open( %{$self->{'DataBase'}->{'OpenOptions'}} );
|
758
|
|
|
|
|
|
|
$self->recreate_index( $tag_name );
|
759
|
|
|
|
|
|
|
}
|
760
|
|
|
|
|
|
|
# ###############################################################################
|
761
|
|
|
|
|
|
|
# Open the specified file.
|
762
|
|
|
|
|
|
|
sub real_create_index {
|
763
|
|
|
|
|
|
|
print "true_create_index\n" if ($DB_File::DB_Database::DEBUG);
|
764
|
|
|
|
|
|
|
my $self = shift;
|
765
|
|
|
|
|
|
|
my %options = @_;
|
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
my %db;
|
768
|
|
|
|
|
|
|
$DB_BTREE->{'flags'} = R_DUP;
|
769
|
|
|
|
|
|
|
$DB_BTREE->{'compare'} = $options{'compare'};
|
770
|
|
|
|
|
|
|
if( tie %db, "DB_File", $options{'FileName'}, O_CREAT, $options{'permits'}, $DB_BTREE ) {
|
771
|
|
|
|
|
|
|
untie %db;
|
772
|
|
|
|
|
|
|
}else{
|
773
|
|
|
|
|
|
|
$self->Error("Error creating index file $options{'FileName'}: $!\n");
|
774
|
|
|
|
|
|
|
return;
|
775
|
|
|
|
|
|
|
}
|
776
|
|
|
|
|
|
|
1; # success
|
777
|
|
|
|
|
|
|
}
|
778
|
|
|
|
|
|
|
# ###############################################################################
|
779
|
|
|
|
|
|
|
# Close the file
|
780
|
|
|
|
|
|
|
sub real_close_index {
|
781
|
|
|
|
|
|
|
my $self = shift;
|
782
|
|
|
|
|
|
|
my @tag_names = @_;
|
783
|
|
|
|
|
|
|
my $tag_name;
|
784
|
|
|
|
|
|
|
foreach $tag_name (@tag_names) {
|
785
|
|
|
|
|
|
|
$self->database_unlock( 'lockfh' => $self->{'Index'}->{$tag_name}->{'lockfh'} );
|
786
|
|
|
|
|
|
|
untie %{$self->{'Index'}->{$tag_name}->{'db'}};
|
787
|
|
|
|
|
|
|
}
|
788
|
|
|
|
|
|
|
delete $self->{'Index'};
|
789
|
|
|
|
|
|
|
}
|
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
# ###############################################################################
|
792
|
|
|
|
|
|
|
# Drop the table
|
793
|
|
|
|
|
|
|
sub drop_index {
|
794
|
|
|
|
|
|
|
my $self = shift;
|
795
|
|
|
|
|
|
|
my @tag_names = map(uc $_, @_);
|
796
|
|
|
|
|
|
|
my $tag_name;
|
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
foreach $tag_name (@tag_names) {
|
799
|
|
|
|
|
|
|
next if( not defined $self->{'Index'}->{$tag_name} );
|
800
|
|
|
|
|
|
|
$self->real_drop_index( $tag_name );
|
801
|
|
|
|
|
|
|
delete $self->{'Index'}->{$tag_name};
|
802
|
|
|
|
|
|
|
delete $self->{'DataBase'}->{'db'}->{'__Index_'.$tag_name};
|
803
|
|
|
|
|
|
|
}
|
804
|
|
|
|
|
|
|
my @index_tags;
|
805
|
|
|
|
|
|
|
my @index_keyfields;
|
806
|
|
|
|
|
|
|
my ($other_tag_name,$key);
|
807
|
|
|
|
|
|
|
while ( ($other_tag_name,$key) = each (%{$self->{'Index'}}) ) {
|
808
|
|
|
|
|
|
|
push (@index_tags, $other_tag_name);
|
809
|
|
|
|
|
|
|
push (@index_keyfields, $key->{'KeyField'});
|
810
|
|
|
|
|
|
|
}
|
811
|
|
|
|
|
|
|
$self->{'DataBase'}->{'db'}->{'__Index'} = $self->csv_combine(@index_tags);
|
812
|
|
|
|
|
|
|
$self->{'DataBase'}->{'db'}->{'__IndexKeyField'} = $self->csv_combine(@index_keyfields);
|
813
|
|
|
|
|
|
|
}
|
814
|
|
|
|
|
|
|
# ###############################################################################
|
815
|
|
|
|
|
|
|
# Drop (unlink) the file
|
816
|
|
|
|
|
|
|
sub real_drop_index {
|
817
|
|
|
|
|
|
|
my $self = shift;
|
818
|
|
|
|
|
|
|
my $tag_name = shift;
|
819
|
|
|
|
|
|
|
my $FileName = $self->{'Index'}->{$tag_name}->{'FileName'};
|
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
undef $self->{'Index'}->{$tag_name};
|
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
if (not unlink $FileName)
|
824
|
|
|
|
|
|
|
{ $self->Error("Error unlinking Index file $FileName: $!\n"); return; };
|
825
|
|
|
|
|
|
|
1;
|
826
|
|
|
|
|
|
|
}
|
827
|
|
|
|
|
|
|
# ###############################################################################
|
828
|
|
|
|
|
|
|
# Recreate Index file.
|
829
|
|
|
|
|
|
|
sub recreate_index {
|
830
|
|
|
|
|
|
|
print "recreate_index\n" if ($DB_File::DB_Database::DEBUG);
|
831
|
|
|
|
|
|
|
my $self = shift;
|
832
|
|
|
|
|
|
|
my @tag_names = map(uc $_, @_);
|
833
|
|
|
|
|
|
|
my $tag_name;
|
834
|
|
|
|
|
|
|
foreach $tag_name (@tag_names) {
|
835
|
|
|
|
|
|
|
if( not defined $self->{'Index'}->{$tag_name} ) {
|
836
|
|
|
|
|
|
|
$self->Error("Index Tag name $tag_name not found.\n");
|
837
|
|
|
|
|
|
|
next;
|
838
|
|
|
|
|
|
|
}
|
839
|
|
|
|
|
|
|
# it has sth wrong: after recreate, should close then open again
|
840
|
|
|
|
|
|
|
# and i don't know why
|
841
|
|
|
|
|
|
|
undef %{ $self->{'Index'}->{$tag_name}->{'db'} };
|
842
|
|
|
|
|
|
|
# my @ids = keys %{$self->{'Index'}->{$tag_name}->{'db'}};
|
843
|
|
|
|
|
|
|
# foreach (0..@ids-1 ) {
|
844
|
|
|
|
|
|
|
# $self->{'Index'}->{$tag_name}->{'fh'}->del($_);
|
845
|
|
|
|
|
|
|
# delete $self->{'Index'}->{$tag_name}->{'db'}->{@ids[$_]};
|
846
|
|
|
|
|
|
|
# }
|
847
|
|
|
|
|
|
|
my ($key, $content_raw);
|
848
|
|
|
|
|
|
|
my $content;
|
849
|
|
|
|
|
|
|
my $indexdata;
|
850
|
|
|
|
|
|
|
while ( ($key, $content_raw) = each( %{$self->{'DataBase'}->{'db'}} ) ) {
|
851
|
|
|
|
|
|
|
if (not $key =~ /^__/ ) {
|
852
|
|
|
|
|
|
|
$content = $self->csv_prase($content_raw);
|
853
|
|
|
|
|
|
|
$indexdata = $self->get_index_string($tag_name, $content);
|
854
|
|
|
|
|
|
|
$self->real_insert_index_record( $tag_name, $indexdata, $key );
|
855
|
|
|
|
|
|
|
}
|
856
|
|
|
|
|
|
|
}
|
857
|
|
|
|
|
|
|
$self->dump_all;
|
858
|
|
|
|
|
|
|
}
|
859
|
|
|
|
|
|
|
1; # success
|
860
|
|
|
|
|
|
|
}
|
861
|
|
|
|
|
|
|
# ###############################################################################
|
862
|
|
|
|
|
|
|
# real_delete_index_record
|
863
|
|
|
|
|
|
|
sub real_delete_index_record {
|
864
|
|
|
|
|
|
|
print "real_delete_index_record\n" if ($DB_File::DB_Database::DEBUG);
|
865
|
|
|
|
|
|
|
my $self = shift;
|
866
|
|
|
|
|
|
|
my ( $tag_name, $content, $id ) = @_;
|
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
$self->{'Index'}->{$tag_name}->{'fh'}->del_dup($content, $id);
|
869
|
|
|
|
|
|
|
}
|
870
|
|
|
|
|
|
|
# ###############################################################################
|
871
|
|
|
|
|
|
|
# real_insert_index_record
|
872
|
|
|
|
|
|
|
sub real_insert_index_record {
|
873
|
|
|
|
|
|
|
print "real_insert_index_record\n" if ($DB_File::DB_Database::DEBUG);
|
874
|
|
|
|
|
|
|
my $self = shift;
|
875
|
|
|
|
|
|
|
my ( $tag_name, $content, $id ) = @_;
|
876
|
|
|
|
|
|
|
print "Index insert : $id -> $content\n" if ($DB_File::DB_Database::DEBUG);
|
877
|
|
|
|
|
|
|
# $DB_BTREE->{'compare'} = $self->get_compare_sub('index' => $tag_name);
|
878
|
|
|
|
|
|
|
$self->{'Index'}->{$tag_name}->{'db'}->{$content} = $id;
|
879
|
|
|
|
|
|
|
}
|
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
# ###############################################################################
|
883
|
|
|
|
|
|
|
# Select the records
|
884
|
|
|
|
|
|
|
# Returns fields of the specified record; optionally names of the required
|
885
|
|
|
|
|
|
|
# fields. If no names are specified, all fields are returned. Returns
|
886
|
|
|
|
|
|
|
# empty list on error.
|
887
|
|
|
|
|
|
|
sub prepare_select {
|
888
|
|
|
|
|
|
|
my $self = shift;
|
889
|
|
|
|
|
|
|
my %options = @_;
|
890
|
|
|
|
|
|
|
if (not defined $self->{'DataBase'}->{'db'} ) {
|
891
|
|
|
|
|
|
|
$self->Error("Data File Not Opened. $!\n");
|
892
|
|
|
|
|
|
|
return;
|
893
|
|
|
|
|
|
|
}
|
894
|
|
|
|
|
|
|
$self->{'Select'}->{'Result'} = [];
|
895
|
|
|
|
|
|
|
$self->{'Select'}->{'Result_Num'} = 0;
|
896
|
|
|
|
|
|
|
my %search = $self->check_field_names_hash(%{$options{'where'}});
|
897
|
|
|
|
|
|
|
my @search = map { $search{$_} } $self->field_names;
|
898
|
|
|
|
|
|
|
my @cut;
|
899
|
|
|
|
|
|
|
if (defined $options{'top'}) {
|
900
|
|
|
|
|
|
|
@cut = (0, 0, $options{'top'});
|
901
|
|
|
|
|
|
|
}elsif (defined $options{'cut'}) {
|
902
|
|
|
|
|
|
|
@cut = (0, @{$options{'cut'}} );
|
903
|
|
|
|
|
|
|
}else {
|
904
|
|
|
|
|
|
|
@cut = (0, 0, -1);
|
905
|
|
|
|
|
|
|
}
|
906
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
my $id;
|
908
|
|
|
|
|
|
|
my @content;
|
909
|
|
|
|
|
|
|
my $i;
|
910
|
|
|
|
|
|
|
my $ok;
|
911
|
|
|
|
|
|
|
if (defined $options{'seek'} and defined $options{'seek'}->{'index'}) {
|
912
|
|
|
|
|
|
|
my $tag = uc $options{'seek'}->{'index'};
|
913
|
|
|
|
|
|
|
if (not defined $self->{'Index'}->{ $tag }) {
|
914
|
|
|
|
|
|
|
$self->Error("Index '$tag' Not Exists. \n");
|
915
|
|
|
|
|
|
|
return;
|
916
|
|
|
|
|
|
|
}
|
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
my ($status, $started);
|
919
|
|
|
|
|
|
|
my ($from, $to) = ($options{'seek'}->{'from'}, $options{'seek'}->{'to'});
|
920
|
|
|
|
|
|
|
my $x = $self->{'Index'}->{ $tag }->{'fh'};
|
921
|
|
|
|
|
|
|
my $compare_sub = $self->get_compare_sub('index' => $tag);
|
922
|
|
|
|
|
|
|
$id = undef;
|
923
|
|
|
|
|
|
|
if (defined $from) { # ?am i right?
|
924
|
|
|
|
|
|
|
$status = $x->seq($from, $id, R_CURSOR);
|
925
|
|
|
|
|
|
|
$started = 1;
|
926
|
|
|
|
|
|
|
}else {
|
927
|
|
|
|
|
|
|
$status = 0;
|
928
|
|
|
|
|
|
|
$started = 0;
|
929
|
|
|
|
|
|
|
}
|
930
|
|
|
|
|
|
|
while ($status == 0) {
|
931
|
|
|
|
|
|
|
last if ( defined $options{'seek'}->{'to'} and &$compare_sub($from, $to) == 1 );
|
932
|
|
|
|
|
|
|
if ($started) {
|
933
|
|
|
|
|
|
|
$ok = 1;
|
934
|
|
|
|
|
|
|
if (defined $options{'where'}) {
|
935
|
|
|
|
|
|
|
(undef, @content) = $self->get_record($id);
|
936
|
|
|
|
|
|
|
foreach $i ( 0..scalar(@{$self->{'DataBase'}->{'data_field_names'}})-1 ) {
|
937
|
|
|
|
|
|
|
next if not defined $search[$i];
|
938
|
|
|
|
|
|
|
if ( $content[$i] !~ /$search[$i]/ ) {
|
939
|
|
|
|
|
|
|
$ok = 0;
|
940
|
|
|
|
|
|
|
last;
|
941
|
|
|
|
|
|
|
}
|
942
|
|
|
|
|
|
|
}
|
943
|
|
|
|
|
|
|
}
|
944
|
|
|
|
|
|
|
if ( $ok ) {
|
945
|
|
|
|
|
|
|
$cut[0]++;
|
946
|
|
|
|
|
|
|
last if ( $cut[2] > 0 and $cut[0] > $cut[2] );
|
947
|
|
|
|
|
|
|
if ( $cut[0] >= $cut[1] ) {
|
948
|
|
|
|
|
|
|
push ( @{$self->{'Select'}->{'Result'}} , $id );
|
949
|
|
|
|
|
|
|
$self->{'Select'}->{'Result_Num'}++;
|
950
|
|
|
|
|
|
|
}
|
951
|
|
|
|
|
|
|
}
|
952
|
|
|
|
|
|
|
}else {
|
953
|
|
|
|
|
|
|
$started = 1;
|
954
|
|
|
|
|
|
|
}
|
955
|
|
|
|
|
|
|
$id = undef;
|
956
|
|
|
|
|
|
|
$status = $x->seq($from, $id, R_NEXT);
|
957
|
|
|
|
|
|
|
}
|
958
|
|
|
|
|
|
|
}else { # no index specified
|
959
|
|
|
|
|
|
|
foreach $id ( keys %{$self->{'DataBase'}->{'db'}} ) {
|
960
|
|
|
|
|
|
|
if (not $id =~ /^__/ ) {
|
961
|
|
|
|
|
|
|
$ok = 1;
|
962
|
|
|
|
|
|
|
if (defined $options{'where'}) {
|
963
|
|
|
|
|
|
|
(undef, @content) = $self->get_record($id);
|
964
|
|
|
|
|
|
|
foreach $i ( 0..scalar(@{$self->{'DataBase'}->{'data_field_names'}})-1 ) {
|
965
|
|
|
|
|
|
|
next if not defined $search[$i];
|
966
|
|
|
|
|
|
|
if ( $content[$i] !~ /$search[$i]/ ) {
|
967
|
|
|
|
|
|
|
$ok = 0;
|
968
|
|
|
|
|
|
|
last;
|
969
|
|
|
|
|
|
|
}
|
970
|
|
|
|
|
|
|
}
|
971
|
|
|
|
|
|
|
}
|
972
|
|
|
|
|
|
|
if ( $ok ) {
|
973
|
|
|
|
|
|
|
$cut[0]++;
|
974
|
|
|
|
|
|
|
last if ( $cut[2] > 0 and $cut[0] > $cut[2] );
|
975
|
|
|
|
|
|
|
if ( $cut[0] >= $cut[1] ) {
|
976
|
|
|
|
|
|
|
push ( @{$self->{'Select'}->{'Result'}} , $id );
|
977
|
|
|
|
|
|
|
$self->{'Select'}->{'Result_Num'}++;
|
978
|
|
|
|
|
|
|
}
|
979
|
|
|
|
|
|
|
}
|
980
|
|
|
|
|
|
|
}
|
981
|
|
|
|
|
|
|
}
|
982
|
|
|
|
|
|
|
}
|
983
|
|
|
|
|
|
|
1;
|
984
|
|
|
|
|
|
|
}
|
985
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
1;
|
988
|
|
|
|
|
|
|
__END__
|