But, for debugging purposes, the LookupJoin constructor can return the auto-generated code of the joiner function. It's done with the option "saveJoinerTo":
saveJoinerTo => \$code,
This snippet will cause the auto-generated code to be placed into the variable $code. This provides a glimpse into the internal workings of the joiner.
This is the joiner code from the first example:
sub # ($inLabel, $rowop, $self) { my ($inLabel, $rowop, $self) = @_; #print STDERR "DEBUGX LookupJoin " . $self->{name} . " in: ", $rowop->printP(), "\n"; my $opcode = $rowop->getOpcode(); # pass the opcode my $row = $rowop->getRow(); my @leftdata = $row->toArray(); my $resRowType = $self->{resultRowType}; my $resLabel = $self->{outputLabel}; my $lookuprow = $self->{rightRowType}->makeRowHash( source => $leftdata[1], external => $leftdata[2], ); #print STDERR "DEBUGX " . $self->{name} . " lookup: ", $lookuprow->printP(), "\n"; my $rh = $self->{rightTable}->findIdx($self->{rightIdxType}, $lookuprow); Carp::confess("$!") unless defined $rh; my @rightdata; # fields from the right side, defaults to all-undef, if no data found my @result; # the result rows will be collected here if (!$rh->isNull()) { #print STDERR "DEBUGX " . $self->{name} . " found data: " . $rh->getRow()->printP() . "\n"; @rightdata = $rh->getRow()->toArray(); } my @resdata = ($leftdata[0], $leftdata[1], $leftdata[2], $leftdata[3], $rightdata[2], ); my $resrowop = $resLabel->makeRowop($opcode, $resRowType->makeRowArray(@resdata)); #print STDERR "DEBUGX " . $self->{name} . " +out: ", $resrowop->printP(), "\n"; Carp::confess("$!") unless defined $resrowop; Carp::confess("$!") unless $resLabel->getUnit()->call($resrowop); }
This is the joiner code from the example with the manual iteration:
sub # ($self, $row) { my ($self, $row) = @_; #print STDERR "DEBUGX LookupJoin " . $self->{name} . " in: ", $row->printP(), "\n"; my @leftdata = $row->toArray(); my $lookuprow = $self->{rightRowType}->makeRowHash( source => $leftdata[1], external => $leftdata[2], ); #print STDERR "DEBUGX " . $self->{name} . " lookup: ", $lookuprow->printP(), "\n"; my $rh = $self->{rightTable}->findIdx($self->{rightIdxType}, $lookuprow); Carp::confess("$!") unless defined $rh; my @rightdata; # fields from the right side, defaults to all-undef, if no data found my @result; # the result rows will be collected here if (!$rh->isNull()) { #print STDERR "DEBUGX " . $self->{name} . " found data: " . $rh->getRow()->printP() . "\n"; @rightdata = $rh->getRow()->toArray(); } my @resdata = ($leftdata[0], $leftdata[1], $leftdata[2], $leftdata[3], $rightdata[2], ); push @result, $self->{resultRowType}->makeRowArray(@resdata); #print STDERR "DEBUGX " . $self->{name} . " +out: ", $result[$#result]->printP(), "\n"; return @result; }
It takes different arguments because now it's not an input label handler but a common function that gets called from both the label handler and the lookup() method. And it collects the rows in an array to be returned instead of immediately passing them on.
This is the joiner code from the example with multiple rows matching on the right side:
sub # ($inLabel, $rowop, $self) { my ($inLabel, $rowop, $self) = @_; #print STDERR "DEBUGX LookupJoin " . $self->{name} . " in: ", $rowop->printP(), "\n"; my $opcode = $rowop->getOpcode(); # pass the opcode my $row = $rowop->getRow(); my @leftdata = $row->toArray(); my $resRowType = $self->{resultRowType}; my $resLabel = $self->{outputLabel}; my $lookuprow = $self->{rightRowType}->makeRowHash( source => $leftdata[1], external => $leftdata[2], ); #print STDERR "DEBUGX " . $self->{name} . " lookup: ", $lookuprow->printP(), "\n"; my $rh = $self->{rightTable}->findIdx($self->{rightIdxType}, $lookuprow); Carp::confess("$!") unless defined $rh; my @rightdata; # fields from the right side, defaults to all-undef, if no data found my @result; # the result rows will be collected here if ($rh->isNull()) { #print STDERR "DEBUGX " . $self->{name} . " found NULL\n"; my @resdata = ($leftdata[0], $leftdata[1], $leftdata[2], $leftdata[3], $rightdata[2], ); my $resrowop = $resLabel->makeRowop($opcode, $resRowType->makeRowArray(@resdata)); #print STDERR "DEBUGX " . $self->{name} . " +out: ", $resrowop->printP(), "\n"; Carp::confess("$!") unless defined $resrowop; Carp::confess("$!") unless $resLabel->getUnit()->call($resrowop); } else { #print STDERR "DEBUGX " . $self->{name} . " found data: " . $rh->getRow()->printP() . "\n"; my $endrh = $self->{rightTable}->nextGroupIdx($self->{iterIdxType}, $rh); for (; !$rh->same($endrh); $rh = $self->{rightTable}->nextIdx($self->{rightIdxType}, $rh)) { @rightdata = $rh->getRow()->toArray(); my @resdata = ($leftdata[0], $leftdata[1], $leftdata[2], $leftdata[3], $rightdata[2], ); my $resrowop = $resLabel->makeRowop($opcode, $resRowType->makeRowArray(@resdata)); #print STDERR "DEBUGX " . $self->{name} . " +out: ", $resrowop->printP(), "\n"; Carp::confess("$!") unless defined $resrowop; Carp::confess("$!") unless $resLabel->getUnit()->call($resrowop); } } }
It's more complicated in two ways: If a match is found, it has to iterate through the whole matching group. And if the match is not found, it still has to produce a result row for a left join with a separate code fragment.
No comments:
Post a Comment