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.

Reply via email to