# RDF::Query::Plan::BasicGraphPattern # ----------------------------------------------------------------------------- =head1 NAME RDF::Query::Plan::BasicGraphPattern - Executable query plan for BasicGraphPatterns. =head1 VERSION This document describes RDF::Query::Plan::BasicGraphPattern version 2.908. =head1 METHODS Beyond the methods documented below, this class inherits methods from the L class. =over 4 =cut package RDF::Query::Plan::BasicGraphPattern; use strict; use warnings; use base qw(RDF::Query::Plan); use Scalar::Util qw(blessed); use RDF::Trine::Statement; ###################################################################### our ($VERSION); BEGIN { $VERSION = '2.908'; } ###################################################################### =item C<< new ( @triples ) >> =cut sub new { my $class = shift; my @triples = map { my @nodes = $_->nodes; $nodes[3] ||= RDF::Trine::Node::Nil->new(); (scalar(@nodes) == 4) ? RDF::Trine::Statement::Quad->new( @nodes ) : RDF::Trine::Statement->new( @nodes ) } @_; my @vars = map { $_->name } grep { $_->isa('RDF::Trine::Node::Variable') } map { $_->nodes } @triples; my @uvars = keys %{ { map { $_ => 1 } @vars } }; my $self = $class->SUPER::new( \@triples ); $self->[0]{referenced_variables} = \@uvars; return $self; } =item C<< execute ( $execution_context ) >> =cut sub execute ($) { my $self = shift; my $context = shift; $self->[0]{delegate} = $context->delegate; if ($self->state == $self->OPEN) { throw RDF::Query::Error::ExecutionError -text => "BGP plan can't be executed twice"; } my $l = Log::Log4perl->get_logger("rdf.query.plan.basicgraphpattern"); $l->trace( "executing RDF::Query::Plan::BasicGraphPattern" ); my @bound_triples; my $bound = $context->bound; if (%$bound) { $self->[0]{bound} = $bound; my @triples = @{ $self->[1] }; foreach my $j (0 .. $#triples) { my @nodes = $triples[$j]->nodes; foreach my $i (0 .. $#nodes) { next unless ($nodes[$i]->isa('RDF::Trine::Node::Variable')); next unless (blessed($bound->{ $nodes[$i]->name })); # warn "pre-bound variable found: " . $nodes[$i]->name; $nodes[$i] = $bound->{ $nodes[$i]->name }; } my $triple = (scalar(@nodes) == 4) ? RDF::Trine::Statement::Quad->new( @nodes ) : RDF::Trine::Statement->new( @nodes ); push(@bound_triples, $triple); } } else { @bound_triples = @{ $self->[1] }; } my @tmp = grep { $_->isa('RDF::Trine::Statement::Quad') and $_->context->isa('RDF::Trine::Node::Variable') } @bound_triples; my $quad = scalar(@tmp) ? $tmp[0]->context : undef; my $model = $context->model; my $pattern = RDF::Trine::Pattern->new( @bound_triples ); $l->trace( "BGP: " . $pattern->sse ); my $iter = $model->get_pattern( $pattern ); if (blessed($iter)) { $self->[0]{iter} = $iter; $self->[0]{quad} = $quad; $self->[0]{nil} = RDF::Trine::Node::Nil->new(); $self->state( $self->OPEN ); } else { warn "no iterator in execute()"; } $self; } =item C<< next >> =cut sub next { my $self = shift; unless ($self->state == $self->OPEN) { throw RDF::Query::Error::ExecutionError -text => "next() cannot be called on an un-open BGP"; } my $q = $self->[0]{quad}; my $iter = $self->[0]{iter}; return undef unless ($iter); while (ref(my $row = $iter->next)) { if (ref(my $bound = $self->[0]{bound})) { @{ $row }{ keys %$bound } = values %$bound; } if (blessed($q)) { # skip results when we were matching over variable named graphs (GRAPH ?g {...}) # and where the graph variable is bound to the nil node # (the nil node is used to represent the default graph, which should never match inside a GRAPH block). my $node = $row->{ $q->name }; if (blessed($node)) { next if ($node->isa('RDF::Trine::Node::Nil')); } } my $result = RDF::Query::VariableBindings->new( $row ); if (my $d = $self->delegate) { $d->log_result( $self, $result ); } return $result; } return; } =item C<< close >> =cut sub close { my $self = shift; unless ($self->state == $self->OPEN) { throw RDF::Query::Error::ExecutionError -text => "close() cannot be called on an un-open BGP"; } delete $self->[0]{iter}; $self->SUPER::close(); } =item C<< distinct >> Returns true if the pattern is guaranteed to return distinct results. =cut sub distinct { return 0; } =item C<< ordered >> Returns true if the pattern is guaranteed to return ordered results. =cut sub ordered { return []; } =item C<< plan_node_name >> Returns the string name of this plan node, suitable for use in serialization. =cut sub plan_node_name { return 'bgp'; } =item C<< plan_prototype >> Returns a list of scalar identifiers for the type of the content (children) nodes of this plan node. See L for a list of the allowable identifiers. =cut sub plan_prototype { my $self = shift; return qw(*T); } =item C<< plan_node_data >> Returns the data for this plan node that corresponds to the values described by the signature returned by C<< plan_prototype >>. =cut sub plan_node_data { my $self = shift; my @triples = @{ $self->[1] }; return @triples; } 1; __END__ =back =head1 AUTHOR Gregory Todd Williams =cut