RDFStore

 view release on metacpan or  search on metacpan

lib/DBD/RDFStore.pm  view on Meta::CPAN

				# a solution would be to have an in-memory model anyway
				#smush() will be better at some point :)
				my $ee = $model->elements;
				while ( my $ss = $ee->each ) {
					$source_model->add( $ss );
					};
			} else {
				#$model = $model->duplicate #which is bad for the moment but allows "to join distributed searches" :-)
				#	if(	( scalar(@{$sth->{'Statement'}->{sources}}) > 0 ) &&
				#		( $model->isRemote ) );
				$source_model=$model;
				};
			};
		unless(defined $source_model) {
			$sth->DBI::set_err( 1, "Cannot process RDF input: $@" );
			return undef;
			};
	} else {
		$source_model=$sth->{'SOURCE_MODEL'};
                };    

        unless(defined $source_model) {
                $sth->DBI::set_err( 1, "Cannot detect RDF input" );
                return undef;
                };

	#print STDERR $source_model->serialize(undef,'RDF/XML')."\n";

	$sth->{'source_model'} = $source_model;

	# zap the whole model
	if(	( $sth->{'Statement'}->getQueryType eq 'DELETE' ) &&
		($#{$sth->{'Statement'}->{resultVars}}==0) &&
		($sth->{'Statement'}->{resultVars}->[0] eq '*') ) {
		my $elements = $sth->{'source_model'}->elements;
		while( my $st = $elements->each ) {	
			unless($sth->{'source_model'}->remove( $st )) {
				$sth->DBI::set_err( 1, "Cannot DELETE triple ". $st->toString );
                		return undef;
				};
			};
		};

        return '0E0'; #we do *not* want to know the number of rows affected at the moment due to efficency problems :)
	};

# fetch the next result set (row)
# This subroutine runs a depth-first like visit of the graph matching the triple patterns (even if we do not really 
# have an in-memory rep of the query process!)
# i.e. the way we visit the graph (backtrack) is "told" by the triple-patterns in the query
# i.e. $sth->{'result'} = ( '?x' => 1, '?y' => Test1 )
#
sub _nextMatch {
        my( $sth, $rpi, $gp, $tpi, %bind ) = @_;

	if($DBD::RDFStore::st::debug>1) {
		print STDERR (" " x $tpi);
		print STDERR "$tpi BEGIN\n";	
		};

	# if we have a previous state try to recover it (this is needed for streaming results)
	my $bind_state = pop @{ $sth->{'binds'} };

	if(	( $bind_state ) && ($DBD::RDFStore::st::debug>1) ) {
		print STDERR (" " x $tpi);
		print STDERR "RECOVER previous state for $tpi\n";
		};

	_nextMatch( $sth, $rpi, $gp, $tpi+1, %{$bind_state} )
		if( $bind_state );

	#we stop on the way if some result was matched already
	if ( scalar(keys %{$sth->{'result'}}) > 0 ) {
		#save actual state on the stack
		push @{ $sth->{'binds'} }, \%bind
			if(	scalar(keys %bind) > scalar(keys %{$gp->{'previous_bindings'}}) and #did we got new columns? (correct??!?!)
				scalar(keys %bind) > 0 );

		if($DBD::RDFStore::st::debug>1) {
			print STDERR (" " x $tpi);
			print STDERR "$tpi GOT NEW RESULT ready (top)\n";
			};

		return;
		};

	if ( $tpi > $#{$gp->{triplePatterns}} ) {
		# actually copy the new result
		map { $sth->{'result'}->{$_} = $bind{$_}; } keys %bind;

		return;
		};

	delete( $sth->{'iterators'}->{$rpi}->{$tpi} ) #retry
		if(     $gp->{'optional'} and #optional block?
			exists $sth->{'iterators'}->{$rpi}->{$tpi} and
               		! $sth->{'iterators'}->{$rpi}->{$tpi}->{itr}->hasnext ); # and previous iterator is over?

	# we want to keep the current iterator state and avoid to run the same query over and over again
	unless( exists $sth->{'iterators'}->{$rpi}->{$tpi} ) {
		$sth->{'iterators'}->{$rpi}->{$tpi} = {};

		#substitute %bind into i-esim triple-pattern if possible and needed

		if($DBD::RDFStore::st::debug>1) {
			print STDERR (" " x $tpi);
			print STDERR "$tpi BEFORE substitute: TP( ",join(',',@{ $gp->{triplePatterns}->[$tpi] })," )\n";
			};

		my @tp;
		my %vars;
		$sth->{'iterators'}->{$rpi}->{$tpi}->{vars} = {};
		$sth->{'iterators'}->{$rpi}->{$tpi}->{optional} = 0;
		my @tp_copy; # local copy of i-esim triple-pattern - needed??!?
		for my $i ( 0..$#{$gp->{triplePatterns}->[$tpi]} ) {
			if($i==0) {
				$sth->{'iterators'}->{$rpi}->{$tpi}->{optional} = $gp->{triplePatterns}->[$tpi]->[$i];
				next;
				};
			push @tp_copy, $gp->{triplePatterns}->[$tpi]->[$i];
			};

lib/DBD/RDFStore.pm  view on Meta::CPAN

	my $XML;
	while( my $xml_match = fetchrow_XML( $sth, $syntax ) ) {
		if($XML) {
			$XML .= $xml_match;
		} else {
			$XML = $xml_match;
			};
		};

	return $XML;
	};

# return string containing the RDF subgraph matching
# syntax: RDF/XML, dawg-results or N-Triples
sub fetchsubgraph_serialize {
        my($sth, $syntax) = @_;

	return
		unless($syntax =~ m#(RDF/XML|N-Triples)#i);

	if($sth->{'RDF_or_XML_stream_finished'}) {
		$sth->{'RDF_or_XML_stream_finished'} = 0;
		return;
		};

	return _fetchrow_RDF_or_XML( $sth, $syntax );
	};

# return string containing the whole RDF graph matching
# syntax: RDF/XML, dawg-results or N-Triples
sub fetchallgraph_serialize {
        my($sth, $syntax) = @_;

	return
		unless($syntax =~ m#(RDF/XML|N-Triples)#i);

	my $RDF;
	while( my $rdf_subgraph = fetchsubgraph_serialize( $sth, $syntax ) ) {
		if($RDF) {
			$RDF .= $rdf_subgraph;
		} else {
			$RDF = $rdf_subgraph;
			};
		};

	return $RDF;
	};

# return RDFStore::Model of matching statements for i-esim iteration
sub fetchsubgraph {
        my($sth) = @_;

	if($sth->{'RDF_or_XML_stream_finished'}) {
		$sth->{'RDF_or_XML_stream_finished'} = 0;
		return;
		};

	return _fetchrow_RDF_or_XML( $sth );
	};

# fetch the whole matching graph in one call (not streaming then)
# return RDFStore::Model of matching statements
sub fetchallgraph {
        my($sth) = @_;

	my $whole_graph;
	while ( my $graph = fetchsubgraph($sth) ) {
		$whole_graph = $graph
			unless($whole_graph);
		my $e = $graph->elements;
		while(my $ss = $e->each) {
			$whole_graph->add($ss);
			};
		};

	return $whole_graph;
	};

# should be streaming
sub _fetchrow_RDF_or_XML {
        my($sth, $syntax) = @_;

	return
		if($sth->{'RDF_or_XML_stream_finished'});

	unless($syntax) {
		$syntax = $sth->{'results'}->{'syntax'}
			if(exists $sth->{'results'}->{'syntax'});
		};

	return
		unless(	(!$syntax) ||
			($syntax =~ m#(RDF/XML|N-Triples|dawg-results|rdf-for-xml|dawg-xml)#i) );

	my $result = '';

	my $mm = new RDFStore::Model; # we want streaming - that's why this...

	# DESCRIBE <URI> are done once in one single subgraph / match
	if(	( $sth->{'Statement'}->getQueryType eq 'DESCRIBE' ) &&
		( grep m/^<([^>]+)>/, @{ $sth->{'Statement'}->{'describes'} }) ) {
		foreach my $d ( @{ $sth->{'Statement'}->{'describes'} } ) {
			next
				unless($d =~ m/^<([^>]+)>/);

			$d = $1;

			my $describe = $sth->{'source_model'}->{rdfstore}->fetch_object(
				$sth->{'FACTORY'}->createResource( $d ) ); #SOURCE / context is not known in SPARQL??

			if($describe) {
				while( my $ss = $describe->each ) {
					$mm->add( $ss );
					};
				};
			};

		$sth->{'RDF_or_XML_stream_finished'} = 1; # must be reset by caller

		if($syntax =~ m#(RDF/XML|dawg-results|rdf-for-xml|dawg-xml)#i) {
			$result .= '<?xml version="1.0"?>'."\n";
			$result .= "\n<!--\n" . $sth->{'results'}->{'comment'} ."\n-->\n\n"
				if(exists $sth->{'results'}->{'comment'});
		} elsif($syntax =~ m/N-Triples/i) {
			$result .= join('# ',split(/\n/,$sth->{'results'}->{'comment'})) ."\n\n"
				if(exists $sth->{'results'}->{'comment'});
			};

		if( $syntax ) {
			$result .= $mm->serialize( undef, $syntax );

			return $result;
		} else {
			return $mm;
			};
		};

	my $first=(scalar( keys %{$sth->{'result'}} ) <= 0 ) ? 1 : 0 ;

	if($first) {
		if($syntax =~ m#(RDF/XML|dawg-results|rdf-for-xml|dawg-xml)#i) {
			$result .= '<?xml version="1.0"?>'."\n";
			$result .= "\n<!--\n" . $sth->{'results'}->{'comment'} ."\n-->\n\n"
				if(exists $sth->{'results'}->{'comment'});
		} elsif($syntax =~ m/N-Triples/i) {
			$result .= join('# ',split(/\n/,$sth->{'results'}->{'comment'})) ."\n\n"
				if(exists $sth->{'results'}->{'comment'});
			};
		if( $sth->{'Statement'}->getQueryType eq 'SELECT' ) {
			if($syntax =~ m/dawg-results/i) {
				# see http://www.w3.org/2001/sw/DataAccess/tests/result-set#
				$sth->{'num_results'}=0;
				$result .=  "<rdf:RDF\n   xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'   xmlns:rs='http://www.w3.org/2001/sw/DataAccess/tests/result-set#'>\n<rs:ResultSet rdf:about=''>\n";
				map {
					my $ff = $_;
					$ff =~ s/^[\?\$]//;
        				$result .= "      <rs:resultVariable>$ff</rs:resultVariable>\n";



( run in 0.813 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )