[21798] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 4002 Volume: 10

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Sun Oct 20 14:10:30 2002

Date: Sun, 20 Oct 2002 11:10:09 -0700 (PDT)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)

Perl-Users Digest           Sun, 20 Oct 2002     Volume: 10 Number: 4002

Today's topics:
        RFC:MLDBM_Handler.pm - Long <d.adamkiewicz@i7.com.pl>
        Digest Administrivia (Last modified: 6 Apr 01) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Sun, 20 Oct 2002 18:03:18 +0200
From: Darek Adamkiewicz <d.adamkiewicz@i7.com.pl>
Subject: RFC:MLDBM_Handler.pm - Long
Message-Id: <aoujh4$g2f$1@news.tpi.pl>

Hello folks
<I appologize for poor English>
I wrote module. This is MLDBM based module which allow
to define/store/manipulate related tables' records.
It requires Storable, MLDBM, SDBM_File, Tie::IxHash.
Belows are two examples from POD - they show how it works,
the second uses Data::Dumper.
Any comments welcome.

Regards
Darek
=============
EXAMPLE1
=============
## DEFINE
perl -e"use MLDBM_Handler;$tree=[qw/f a 
b/];$it=MLDBM_Handler->init(q/f/,$tree);"
## ADD
perl -e"use 
MLDBM_Handler;$it=MLDBM_Handler->init(q/f/);$it->set_rows([{a=>11,b=>12},{a=>12,b=>13}]);"
## GET
perl -e"use 
MLDBM_Handler;$it=MLDBM_Handler->init(q/f/);$g=$it->get_rows;for(@$g){print 
qq/@{[%$_]}\n/}"
===============
EXAMPLE2
===============
use MLDBM_Handler;

@common = qw/created updated/; ## option

$tree = [qw/filename1 field1/,
		[qw/filename2 field2/,[qw/filename3 field3/]]
	];

MLDBM_Handler::add_common($tree,\@common); ## option

%obj = ();
$obj{filename1} = MLDBM_Handler->init("filename1", $tree);
$obj{filename2} = MLDBM_Handler::db("filename2");
$obj{filename3} = MLDBM_Handler::db("filename3");

foreach (qw/33331 33332 33333/) {
	my $href;
	$href->{field3} = $_;
	push(@$aref, $href);
}

## NOTE: order of following statements is crucial to set all information
## needed about relations between those rows

@set = $obj{filename3}->set_rows($aref); ## append three rows
print "@set\n";

$href->{filename3} = [@set]; ## store indices of those rows
$href->{field2} = "22222";
@set = $obj{filename2}->set_rows([$href]);

$href->{filename2} = [@set];
$href->{field1} = "11111";
$obj{filename1}->set_rows([$href]);

$aref1 = $obj{filename1}->get_ext_rows; ## get everything
	
use Data::Dumper;
print Dumper($aref1);
	
$obj{filename3}->delete(0, -1); ## first and last row

$aref2 = $obj{filename2}->get_ext_rows; ##
print Dumper($aref2);

@flds = $obj{filename3}->flds;
print "@flds\n";
__END__

===============================================
package MLDBM_Handler;

use vars qw/$VERSION/;
$VERSION = '0.13';#

use strict;
use MLDBM qw/SDBM_File Storable/;
use MLDBM::Serializer::Storable; ##
use Storable qw/dclone/;
use SDBM_File; ##
use Fcntl;
use Carp::Heavy; ##
use Tie::IxHash;

our %db;

sub db {
	my $file = shift;
	if (ref($db{$file}) =~ /MLDBM_Handler/) {
		return $db{$file};
	} elsif (ref($db{$file}) =~ /ARRAY/) {
		return init(__PACKAGE__,$file, @{ $db{$file} });
	} else {
		return undef;#Carp?
	}
}

sub init {
	my $this = shift;
	my $class = ref($this)||$this;
	my ($file, $tree, $branch, $mode, $perms) = @_;
	my $self = {};
	$self->{FILE} = $file;

	$mode ||= (O_CREAT|O_RDWR);
	$perms  ||= 0666;
	tie %{$self->{TIEHASH}}, 'MLDBM', $file, $mode, $perms or die $!;
	
	my $proc;## to be processed unless $branch
	unless ($proc = ${$self->{TIEHASH}}{tree}) {
	##	save
		${$self->{TIEHASH}}{tree} = $tree;
		$proc = $tree;
	}	

	return $proc if !defined($proc);	
	
	my %tables;

	unless ($branch) {
		my $clone = dclone($proc);
		set_tables_data(\%tables, $proc);
		my @extfiles = grep !/^$file$/, keys %tables;
		if ( @extfiles>0 ) {
		##	so there is at least one file connected
			foreach (@extfiles) {
				$db{$_} = [$clone, $tables{$_} ];
			}
		}
		@{$self->{FLDS}} = @{ $tables{$file}{FLDS} };
		@{$self->{DOWN}} = @{ $tables{$file}{DOWN} };
		$self->{UP} = $tables{$file}{UP};
	} else {
		@{$self->{FLDS}} = @{ $branch->{FLDS} };
		@{$self->{DOWN}} = @{ $branch->{DOWN} };
		$self->{UP} = $branch->{UP};
	}
##	IMPLICITLY ADD FIELD IF EXISTS SUPERIOR FILE - FIELD IS NOT CONTAINED 
IN $tree!!!
##	IT'S FOR delete
	unshift(@{$self->{FLDS}}, "nodes")
		if defined $self->{UP};	
		
	my @numkeys = map {$_, undef}  sort {$a<=>$b} grep /^\d+$/ && $_, keys 
%{$self->{TIEHASH}};
	$self->{NUMKEYS} = Tie::IxHash->new( @numkeys );

	bless $self, $class;
	$db{$file} = $self;
	return $self;
}

sub set_tables_data {
	my ($tables, $reft, $up) = @_;
	my $first = shift @$reft;	
	$tables->{$first}{UP} = $up;
	@{$tables->{$first}{DOWN}} = ();
	foreach (@$reft) {
		if (ref($_) =~ /ARRAY/) {
			push(@{$tables->{$first}{FLDS}}, $_->[0]);
		##	array of ref
			push(@{$tables->{$first}{DOWN}}, $tables->{$first}{FLDS}[-1]);
			set_tables_data($tables, $_, $first);
		} else {
			push(@{$tables->{$first}{FLDS}}, $_);
		}
	}
}

## ultility
sub add_common {
	my ($reft, $common) = @_;
	my $first = shift @$reft;
	unshift(@$reft, $first, @$common);
	foreach (@$reft) {
		if (ref($_) =~ /ARRAY/) {
			add_common($_, $common);		
		}
	}
}

sub _get_rows {
## 	ext:true - get external values, false - don't
	my ($self, $ext, @list) = @_;
	my @indices = ();
	my $ret = [];

	@list = grep /^\-?\d+$/, @list;
	
	@list = $self->{NUMKEYS}->Indices($self->{NUMKEYS}->Keys) if @list == 0;

	my @spec = $self->{NUMKEYS}->Keys( @list );

	if ( defined($self->{UP}) ) {
		if (ref($db{$self->{UP}}) =~ /ARRAY/) {
			init(__PACKAGE__, $self->{UP}, @{ $db{$self->{UP}} });
		}
		die "hash element \"$self->{UP}\" exists while superior file object 
doesn't"
			unless defined $db{$self->{UP}};
	}

	for(my $i=0; $i<=$#spec; $i++) {
		if (defined $spec[$i]) {
			my $href = {}; ##-
			@{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };	
			##+ 0.09
			if ( exists($href->{nodes}) ) {## && defined($href->{nodes})
				if (defined $db{$self->{UP}}) {
					my @temp = unpack "n*", $href->{nodes};
					shift @temp;
					$href->{nodes} = [@temp];
					@{$href->{nodes}} = grep defined($_), 
$db{$self->{UP}}->{NUMKEYS}->Indices( @{$href->{nodes}} )
						if @temp>0;
				} else {
					die "hash element \"nodes\" exists and isn't empty while superior 
file object doesn't exist";
				}
			} ##+ 0.09
			foreach my $e (@{$self->{DOWN}}) {
				my @temp = unpack "n*", $href->{$e};
				shift @temp;
				$href->{$e} = [@temp];
				if (@temp) {
					if (ref($db{$e}) =~ /ARRAY/) {
						init(__PACKAGE__, $e, @{ $db{$e} });
					}
					@{$href->{$e}} = grep defined($_), $db{$e}->{NUMKEYS}->Indices( 
@{$href->{$e}} );
					if ($ext && @{$href->{$e}}>0) {
						 @{$href->{$e}} = _get_rows($db{$e}, $ext, @{$href->{$e}});
					}
				}	
			}
			push(@$ret, $href);
			push(@indices, $list[$i]);
		}
	}
	return wantarray?($ret, @indices):$ret;
}

##	obj->get_rows(-1); obj->get_rows; obj->get_rows(0,3,5);
##	get whole rows data
sub get_ext_rows {
	my ($self, @list) = @_;
	return _get_rows($self,1,@list);
}

##	obj->get_rows(-1); obj->get_rows; obj->get_rows(0,3,5);
##	get rows data
sub get_rows {
	my ($self, @list) = @_;
	return _get_rows($self,0,@list);
}

##	obj->set_rows(to); append
##	obj->set_rows(to, -1)
##	if LIST supplied it sets every existed element for list
##	if LIST not supplied it sets every element supplied
sub set_rows {
	my ($self, $to, @list) = @_;
##	you should check wheter it is non-duplicate elements list
	my @set = ();

	@list = grep /^\-?\d+$/,@list;#+0.12
	if (@list == 0) {
		my $next = $self->{NUMKEYS}->Length;
		@list = ($next..$next+$#{$to});
	}
	my @spec = $self->{NUMKEYS}->Keys( @list );
	
	if ( defined($self->{UP}) ) {
		if (ref($db{$self->{UP}}) =~ /ARRAY/) {
			init(__PACKAGE__, $self->{UP}, @{ $db{$self->{UP}} });
		}
		die "hash element \"$self->{UP}\" exists while superior file object 
doesn't"
			unless defined $db{$self->{UP}};
	}

	my %ext_set;
	my %ext_del;
	my ($created, $updated) = k2i($self->{FLDS},[qw/created updated/]);

	for(my $i=0; $i<@spec; $i++) {
		my $aref = [];
		if (defined $to->[$i]) {
			if (!defined $spec[$i]) {
				my ($last) = $self->{NUMKEYS}->Keys(-1);
				$last = 0 unless defined $last;
				my $last_index = $self->{NUMKEYS}->Length-1;
				$spec[$i] = $last+($list[$i]<1?0:$list[$i])-$last_index;
				##print "\$last+(\$list[\$i]<1?0:\$list[\$i])-\$last_index\n";
				##print $last,"\+",($list[$i]<1?0:$list[$i]),"\-",$last_index,"\n";
				foreach ($last+1..$spec[$i]-1) {
				## AUTOVIVIFICATION IF GAP!!!
					${ $self->{TIEHASH} }{$_} = [];
					$self->{NUMKEYS}->Push($_=>undef);
				}
				$self->{NUMKEYS}->Push($spec[$i]=>undef);
				$to->[$i]->{created} = time if defined $created;
				$to->[$i]->{updated} = undef if defined $updated;#?
				## $to->[$i]->{nodes} = undef if exists $to->[$i]->{nodes};#?
				#print "not defined created:$to->[$i]->{created} 
updated:$to->[$i]->{updated}\n"
			} else {
				if (@{$self->{DOWN}}) {
				##	CLEAN external "nodes"
					my $href = {};##+
					@{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };##+
					foreach my $e (@{$self->{DOWN}}) {
						if ( defined($href->{$e}) ) {
							my @temp = unpack "n*", $href->{$e};
							shift @temp;
							foreach my $el ( @temp ) {
								push(@{ $ext_del{$e} }, [ $el, $spec[$i] ]);
							}
						}
					}
				}
				$to->[$i]->{updated} = time if defined $updated;
				#print "defined created:$to->[$i]->{created} 
updated:$to->[$i]->{updated}\n"
			}
			if (@{$self->{DOWN}}) {
				foreach my $e (@{$self->{DOWN}}) {
					my @temp;
					if (!defined($to->[$i]->{$e})) {
					##	implictly accept 'undef'				

					##	array of indices of external rows
					} elsif (ref($to->[$i]->{$e}) =~ /ARRAY/) {
						shift @{ $to->[$i]->{$e} }
							if ref($to->[$i]->{$e}->[0]) =~ /ARRAY/;

						if (ref($db{$e}) =~ /ARRAY/) {
							init(__PACKAGE__, $e, @{ $db{$e} });
						}	

						if (defined $db{$e}) {
						##	get numkeys of supplied indices
							@temp = $db{$e}->{NUMKEYS}->Keys( @{$to->[$i]->{$e}} );#0.12
						} else {
							die "hash element \"$e\" exists and isn't empty while superior 
file object doesn't exist";
						}

						foreach my $el ( @temp ) {
						##	external row numkey, row numkey
							push(@{ $ext_set{$e} }, [ $el, $spec[$i] ]);
						}
					} else {
						die "hash $e element should be array ref!!!";
					}
					#push(@temp, 0) if @temp==0;
					@temp = grep $_, @temp;
					unshift(@temp,0);
					$to->[$i]->{$e} = pack "n*", @temp;
				}
			}
			##+ 0.09
			if (defined $self->{UP}) {
				my @temp;
				if (!defined($to->[$i]->{nodes})) {
				## implicitly accept 'undef'
				} elsif ( ref($to->[$i]->{nodes}) =~ /ARRAY/ ) {
					@temp = $db{$self->{UP}}->{NUMKEYS}->Keys( @{$to->[$i]->{nodes}} );
				} else {
					die "hash \"nodes\" element should be array ref!!!";
				}
				@temp = grep $_, @temp;
				unshift(@temp,0);
				$to->[$i]->{nodes} = pack "n*", @temp;
			} ##+ 0.09
			@$aref = @{$to->[$i]}{ @{$self->{FLDS}} };
		} else {
			last;
		}
		${ $self->{TIEHASH} }{$spec[$i]} = $aref;
		push(@set, $list[$i]);
	}

	ch_nodes(\%ext_del, 1); ## DELETE
	ch_nodes(\%ext_set);    ## SET
##	RETURNS ARRAY OF ROW ELEMENT INDICES
	return @set;
}

##	DELETE OR SET
sub ch_nodes {
	my ($href, $what) = @_;
	ch_field($href, $what, "nodes");
}

##	DELETE OR SET
sub ch_field {
	my $href = shift;
	my $what = shift; ## false - SET, true - DELETE
	my $field = shift;
	my @files = keys %$href;
	if (@files>0) {
		foreach my $f (@files) {
			if (ref($db{$f}) =~ /ARRAY/) {
				init(__PACKAGE__, $f, @{ $db{$f} });
			}
			my $idx = k2i($db{$f}->{FLDS},[$field]);
			foreach my $el ( @{$href->{$f}} ) {
				my $temp = ${ $db{$f}->{TIEHASH} }{$el->[0]};
				my @temp = unpack "n*", $temp->[$idx];
				@temp = grep $_!=$el->[1], @temp
						if $what;	## DELETE
				push(@temp, $el->[1])
						unless $what;	## SET
				@temp = grep /^\d+/ && $_, @temp;##+0.11
				unshift(@temp, 0);
				$temp->[$idx] = pack "n*", @temp;
				${ $db{$f}->{TIEHASH} }{$el->[0]} = $temp;
			}
		}
	}
}

sub delete {
	my ($self, @list) = @_;
	my  @indices; ##+$aref

	@list = grep /^\-?\d+$/, @list;#+0.12

	@list = $self->{NUMKEYS}->Indices($self->{NUMKEYS}->Keys) if @list == 0;

	my @spec = $self->{NUMKEYS}->Keys( @list );

	my %up_del;
	my %down_del;

	for(my $i=0; $i<@spec; $i++) {
		if (defined $spec[$i]) {
			my $href = {}; ##-
			@{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };	
			if (defined $self->{UP}) {
				if ( exists($href->{nodes}) ) {#&& defined($href->{nodes})
				##	fetch numkeys from pack'ed read structure
					my @temp = unpack "n*", $href->{nodes};
					shift @temp;
					$href->{nodes} = [@temp];
					foreach my $el ( @{$href->{nodes}} ) {
				##	external rows indentification keys, key to delete
						push(@{ $up_del{$self->{UP}} }, [ $el, $spec[$i] ]);
					}
				}
			}
			if (@{$self->{DOWN}}) {
			##	CLEAN "nodes"
				foreach my $e (@{$self->{DOWN}}) {
					my @temp = ();
					if (defined $db{$e}) {
						@temp = unpack "n*", $href->{$e};
						shift @temp;
					} else {
						die "hash element \"$e\" exists while superior file object doesn't";
					}
					foreach my $el ( @temp ) {
						push(@{ $down_del{$e} }, [ $el, $spec[$i] ]);
					}
				}
			}
			delete ${$self->{TIEHASH}}{$spec[$i]}; ## DELETE	
			$self->{NUMKEYS}->Delete( $spec[$i] ); ## 0.12
			push(@indices, $list[$i]);
		}
	}
	ch_field(\%up_del, 1, $self->{FILE}); ## DELETE
	ch_nodes(\%down_del, 1); ## DELETE
	return @indices;
}

sub key2idx {
	my ($self, @args) = @_;
	return k2i($self->{NUMKEYS},\@args);
}

sub k2i {
	my ($keys, $args) = @_;
	my %conv = ();
	@conv{ @$keys } = (0..$#{$keys});
	return wantarray ? @conv{@$args} : $conv{$args->[0]};	
}

sub idx2key {
	my ($self, @indices) = @_;
	return grep /^\d+/ && $_, @{$self->{NUMKEYS}}[@indices];
}

sub file {
	my $self = shift;
	return $self->{FILE};
}

sub flds {
	my $self = shift;
	return @{$self->{FLDS}};
}

sub up {
	my $self = shift;
	return $self->{UP};
}

sub down {
	my $self = shift;
	return @{$self->{DOWN}};
}

sub numkeys {
	my $self = shift;
	return $self->{NUMKEYS}->Keys;
}

sub last {
	my $self = shift;
	return $self->{NUMKEYS}->Length-1;
}

sub name {
	my $self = shift;
	if (@_) {
		$self->{NAME} = shift;
	}
	return $self->{NAME};
}

1;
__END__
=head1 NAME

MLDBM_Handler - create and mainpulate structured MLDBM tied hash references

=head1 SYNOPSIS

	use MLDBM_Handler;

	@common = qw/created updated/; ## optional

	$tree = [FILENAME, FIELD_NAMES_LIST,
			[FILENAME1, FIELD_NAMES_LIST1,
				[FILENAME2, FIELD_NAMES_LIST2],
				...
			],
			...
		];

	MLDBM_Handler::add_common($tree,\@common); ## optional

	%obj = ();
	$obj{FILENAME} = MLDBM_Handler->init(FILENAME, $tree);
	## or
	$obj{FILENAME} =
		MLDBM_Handler->init(FILENAME, $tree, undef, $mode, $perms);
	## or
	$obj{FILENAME} = MLDBM_Handler->init(FILENAME); ## NEVER FIRST TIME

	@down = $obj{FILENAME}->down; ## (FILENAME1)

	$obj{FILENAME1} = MLDBM_Handler::db(FILENAME1);

	$file = $obj{FILENAME}->file; ## FILENAME

	@down = $obj{FILENAME1}->down; ## (FILENAME2)

	$obj{FILENAME2} = MLDBM_Handler::db(FILENAME2);

	@set_rows_indices =
		$obj{FILENAMEn}->set_rows(ARRAYREF_OF_HASHREF,[LIST]);

	$up = $obj{FILENAME2}->up; ## FILENAME1
	
	$aref_of_href = $obj{FILENAME}->get_ext_rows;
	## or
	($aref_of_href, @get_rows_indices) = $obj{FILENAME}->get_ext_rows;

	$aref_of_href1 = $obj{FILENAME}->get_rows; ## NOT THE SAME AS ABOVE
	## or
	($aref_of_href1, @get_rows_indices1) =  $obj{FILENAME}->get_rows;
	
	$obj{FILENAMEn}->delete([LIST]);
	$obj{FILENAMEn}->last;


=head1 DESCRIPTION

MLDBM_Handler is MLDBM module wrapper which allow to create/manipulate 
associated
files' structure. For each file (table) is defined set of field's names 
which
comprises row (record). Set of fields is the same for all rows. C<nodes> 
is restricted
field's name and shouldn't be specified explicitly, C<created> and 
C<updated> fields
are handled internally - if they are specified then: 1)on I<append row> 
operation C<time>
function value is set to C<created> row field in file 2)on I<write to 
existing row> operation
C<time> function value is set to C<updated> row field in file. Data get 
from and set to
rows are in form of I<array reference of hash references> where hash 
keys are fields' names.
There are fields' names that are FILENAMES of interior files. Those 
fields contain
array reference of indices (similar to elements' array indices) 
identifying particular row
in interior file. The fields MUST be set to proper values (indices) 
before write rows
C<set_rows> operation.

=head2 UTILITY

=over 4

=item MLDBM_Handler::add_common

Utility sub - allow to arbitrary field's names (except C<nodes>) i.e.
C<created, updated, blahblah> to be added as next after first element 
(filename) of all
arrays pointed by C<$tree> data structure before C<$tree> will be 
processed by
C<init> method.

=back

=head2 CONSTRUCTOR(S)

=over 4

=item init

This method creates file data structures in file FILENAME according to 
passed
array reference C<$tree> if the structures don't exists - in that case you
may change default mode C<O_CREAT|O_RDWR> or perms C<0666> if you 
specify them.
Afterwards C<init> read these structures and builds object from them. 
C<$tree>
defines hierarchical structure of associated files.

=item MLDBM_Handler::db

Returns object reference of interior file FILENAME. If underlaying data 
structure in
file doesn't exist then it's created. Returns C<undef> on failure. Must 
be invoked
after C<init>.

=back

=head2 METHODS

The following methods may be applied to object references returned by 
both C<init> and
C<MLDBM_Handler::db> CONSTRUCTORS

=item flds

Returns array of all field's names of row on which operate object.

=item last

Returns last row's index or -1 if there are no rows.

=item down

Returns field's names that are FILENAMES of interior files or empty 
array otherwise.

=item up

Returns field's name of superior file or C<undef> otherwise.

=item set_rows

Sets array reference of hash references as data rows in corresponding 
file according
to indices list if supplied or at the end of file otherwise. If LIST is 
supplied then
it sets every existed element for LIST. If LIST is NOT supplied then it 
sets every
element supplied. May cause autovivification effect - adds rows - if 
there is a gap between
last row's index and supplied index of unexisted row. i.e. while last 
index (1) if
supplied (3) then it will add (2, 3) rows. Returns array of set rows 
indices.

=item get_ext_rows

Gets data rows specified by indices list (or all row if list is not 
supplied) and returns
array reference of hash references. If row field's names comprises 
FILENAMES of interior
files then corresponding hash value will contain array reference - first 
element of array
will be array reference of hash refrences (if that hash keys contain 
FILENAMES of interior
files then it'll contain appropriate array reference and so on) and the 
rest of elements
will be list of appropriate external file rows indices.

=item get_rows

Gets data rows specified by indices list (or all row if list is not 
supplied) and returns
array reference of hash references. If row field's names comprises 
FILENAMES of interior
files then corresponding hash value will contain array reference - the 
array will contain
external file rows indices.

=item delete

Deletes rows of specified indices or all rows if no arguments. If for 
row to be deleted
exists field C<nodes> and it contains array of numeric values then those 
values are
indices identifying particular external file rows and data in those 
external file rows
pointing to that row will be deleted too.

=item file

Returns FILENAME of file associated with object.

=item name

Sets/gets name of object.

=head1 EXAMPLE1

	## DEFINE
	perl -e"use MLDBM_Handler;$tree=[qw/f a 
b/];$it=MLDBM_Handler->init(q/f/,$tree);"
	## ADD
	perl -e"use 
MLDBM_Handler;$it=MLDBM_Handler->init(q/f/);$it->set_rows([{a=>11,b=>12},{a=>12,b=>13}]);"
	## GET
	perl -e"use 
MLDBM_Handler;$it=MLDBM_Handler->init(q/f/);$g=$it->get_rows;for(@$g){print 
qq/@{[%$_]}\n/}"

=head1 EXAMPLE2

	use MLDBM_Handler;

	@common = qw/created updated/; ## option

	$tree = [qw/filename1 field1/,
			[qw/filename2 field2/,[qw/filename3 field3/]]
		];

	MLDBM_Handler::add_common($tree,\@common); ## option

	%obj = ();
	$obj{filename1} = MLDBM_Handler->init("filename1", $tree);
	$obj{filename2} = MLDBM_Handler::db("filename2");
	$obj{filename3} = MLDBM_Handler::db("filename3");

	foreach (qw/33331 33332 33333/) {
		my $href;
		$href->{field3} = $_;
		push(@$aref, $href);
	}

	## NOTE: order of follownig statements is crucial to set all information
	## needed about relations between those rows

	@set = $obj{filename3}->set_rows($aref); ## append three rows
	print "@set\n";

	$href->{filename3} = [@set]; ## store indices of those rows
	$href->{field2} = "22222";
	@set = $obj{filename2}->set_rows([$href]);

	$href->{filename2} = [@set];
	$href->{field1} = "11111";
	$obj{filename1}->set_rows([$href]);

	$aref1 = $obj{filename1}->get_ext_rows; ## get everything
	
	use Data::Dumper;
	print Dumper($aref1);
	
	$obj{filename3}->delete(0, -1); ## first and last row

	$aref2 = $obj{filename2}->get_ext_rows; ##
	print Dumper($aref2);

	@flds = $obj{filename3}->flds;
	print "@flds\n";

=head1 CAVEATS

Slow, slow, slow.

=head1 AUTHOR

Darek Adamkiewicz E<lt>d.adamkiewicz@i7.com.plE<gt>

=head1 COPYRIGHT

Copyright (c) Darek Adamkiewicz. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

Please feel free to e-mail me if it concerns this module.

=head1 VERSION

Version 0.13   12 OCT 2002

=head1 SEE ALSO

MLDBM, SDBM_File, Storable

=cut



------------------------------

Date: 6 Apr 2001 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 6 Apr 01)
Message-Id: <null>


Administrivia:

The Perl-Users Digest is a retransmission of the USENET newsgroup
comp.lang.perl.misc.  For subscription or unsubscription requests, send
the single line:

	subscribe perl-users
or:
	unsubscribe perl-users

to almanac@ruby.oce.orst.edu.  

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

To request back copies (available for a week or so), send your request
to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
where x is the volume number and y is the issue number.

For other requests pertaining to the digest, send mail to
perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
sending perl questions to the -request address, I don't have time to
answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V10 Issue 4002
***************************************


home help back first fref pref prev next nref lref last post