On Sat, Jun 25, 2005 at 12:21:41PM -0400, Sam Tregar wrote:
> On Thu, 23 Jun 2005, Sam Tregar wrote:
>
> > That looks do-able. I'll try to work up a patch in the next couple
> > days. I'll include the DBI->installed_drivers() method as well, if
> > that's ok.
>
> Here it is. I've implemented a ChildHandles attribute and the
> installed_drivers() method. There is one bug left, marked "BROKEN" in
> the test script. It concerns what happens when you try to retrieve
> ChildHandles for a handle that doesn't have any children. Right now
> you get an error like this:
>
> Can't get DBI::db=HASH(0x9bd53bc)->{ChildHandles}: unrecognised
> attribute at /home/sam/module-dev/DBI-1.48/blib/lib/DBD/ExampleP.pm
> line 221.
>
> I'm sure I could fix this by adding ChildHandles to the list of
> attributes in DBI.xs, but you said you didn't think that would be
> necessary. Ideas?
Idea: I was wrong :) Adding ChildHandles to the list of attributes in
the attribute get code in DBI.xs is the right thing to do.
> + # add to the parent's ChildHandles
> + if ($HAS_WEAKEN && $parent) {
> + my $handles = $parent->{ChildHandles} ||= [];
> +
> + # purge destroyed handles occasionally (the easy way to do
> + # this with grep undoes the weak-refs, for some reason)
> + if (@$handles % 120 == 0 and @$handles) {
> + my $last = $#$handles;
> + for my $i (0 .. $#$handles) {
> + last if $i > $last;
> + next if defined $handles->[$i];
> + splice @$handles, $i, 1;
> + $last--;
> + }
Did my one-liner not work?
@$ch = grep { $_ } @$ch if @$ch % 120 == 0 && @$ch;
It's much smaller/faster/simpler.
> + }
> + push @$handles, $h;
> + Scalar::Util::weaken($handles->[-1]);
> + }
> +=item C<installed_drivers>
> +
> + %drivers = DBI->installed_drivers();
> +
> +Returns a hash mapping driver names to driver handles.
Slight tweak:
Returns a list of driver name and driver handle pairs for all
installed drivers. The driver name does not include the 'DBD::' prefix.
> +=item C<ChildHandles> (array ref)
> +
> +The ChildHandles attribute contains a reference to an array of all the
> +handles created by this handle which are still accessible. The
> +contents of the array are weak-refs and will become undef when the
> +handle goes out of scope. C<ChildHandles> is only available if you
> +have the L<Scalar::Util|Scalar::Util> module installed and
> +C<Scalar::Util::weaken()> is working.
> +
> +For example, to enumerate all driver handles, database handles and
> +statement handles:
> +
> + my %drivers = DBI->installed_drivers();
> + foreach my $drh (values %drivers) {
> + print "DRH: $drh\n";
> + foreach my $dbh (@{$drh->{ChildHandles}}) {
> + next unless defined $dbh;
> + print "DBH: $dbh\n";
> + foreach my $sth (@{$dbh->{ChildHandles}}) {
> + next unless defined $sth;
> + print "STH: $sth\n";
> + }
> + }
> + }
Could also include a recursive version (untested):
sub show_child_handles {
my ($h, $level) = @_;
foreach my $ch (grep { defined } @{$h->{ChildHandles}}) {
printf "%sh %s %s\n", $ch->{Type}, ("\t" x $level||=0), $ch;
show_child_handles($ch, $level+1);
}
}
Thanks Sam.
Tim.
p.s. I've just spotted that $h->{Type} isn't documented. Could you add
that to your patch? $h->{Type} just returns "dr", "db", or "st"
depending on the type of the handle. Thanks.