line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# RDF::Query |
2
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
RDF::Query - A complete SPARQL 1.1 Query and Update implementation for use with RDF::Trine. |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 VERSION |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
This document describes RDF::Query version 2.915_01. |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 SYNOPSIS |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# SPARQL SELECT Query |
15
|
|
|
|
|
|
|
my $query = RDF::Query->new( 'SELECT * WHERE ...' ); |
16
|
|
|
|
|
|
|
my $iterator = $query->execute( $model ); |
17
|
|
|
|
|
|
|
while (my $row = $iterator->next) { |
18
|
|
|
|
|
|
|
# $row is a HASHref containing variable name -> RDF Term bindings |
19
|
|
|
|
|
|
|
print $row->{ 'var' }->as_string; |
20
|
|
|
|
|
|
|
} |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# SPARQL CONSTRUCT/DESCRIBE Query |
23
|
|
|
|
|
|
|
my $query = RDF::Query->new( 'CONSTRUCT { ... } WHERE ...' ); |
24
|
|
|
|
|
|
|
my $iterator = $query->execute( $model ); |
25
|
|
|
|
|
|
|
while (my $st = $iterator->next) { |
26
|
|
|
|
|
|
|
# $st is a RDF::Trine::Statement object representing an RDF triple |
27
|
|
|
|
|
|
|
print $st->as_string; |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# SPARQL ASK Query |
31
|
|
|
|
|
|
|
my $query = RDF::Query->new( 'ASK WHERE ...' ); |
32
|
|
|
|
|
|
|
my $iterator = $query->execute( $model ); |
33
|
|
|
|
|
|
|
my $bool = $iterator->get_boolean; |
34
|
|
|
|
|
|
|
if ($bool) { |
35
|
|
|
|
|
|
|
print "Yes!\n"; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# RDQL Query |
39
|
|
|
|
|
|
|
my $query = new RDF::Query ( $rdql, { lang => 'rdql' } ); |
40
|
|
|
|
|
|
|
my @rows = $query->execute( $model ); # in list context, returns all results |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head1 DESCRIPTION |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
RDF::Query allows SPARQL and RDQL queries to be run against an RDF model, |
45
|
|
|
|
|
|
|
returning rows of matching results. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
See L<http://www.w3.org/TR/rdf-sparql-query/> for more information on SPARQL. |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
See L<http://www.w3.org/Submission/2004/SUBM-RDQL-20040109/> for more |
50
|
|
|
|
|
|
|
information on RDQL. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 CHANGES IN VERSION 2.900 |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
The 2.9xx versions of RDF::Query introduce some significant changes that will |
55
|
|
|
|
|
|
|
lead to a stable 3.000 release supporting SPARQL 1.1. Version 2.902 introduces |
56
|
|
|
|
|
|
|
the SPARQL 1.1 features up to date with the SPARQL 1.1 working drafts as of its |
57
|
|
|
|
|
|
|
release date. Version 2.902 also is the first version to require use of |
58
|
|
|
|
|
|
|
RDF::Trine for the underlying RDF store. This change means that RDF::Core is |
59
|
|
|
|
|
|
|
no longer supported, and while Redland is still supported, its handling of |
60
|
|
|
|
|
|
|
"contexts" (named graphs) means that existing RDF triples stored in Redland |
61
|
|
|
|
|
|
|
without associated contexts will not be accessible from RDF::Query. |
62
|
|
|
|
|
|
|
See L<RDF::Trine::Store> for more information on supported backend stores. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=head1 CHANGES IN VERSION 2.000 |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
There are many changes in the code between the 1.x and 2.x releases. Most of |
67
|
|
|
|
|
|
|
these changes will only affect queries that should have raised errors in the |
68
|
|
|
|
|
|
|
first place (SPARQL parsing, queries that use undefined namespaces, etc.). |
69
|
|
|
|
|
|
|
Beyond these changes, however, there are some significant API changes that will |
70
|
|
|
|
|
|
|
affect all users: |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=over 4 |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=item Use of RDF::Trine objects |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
All nodes and statements returned by RDF::Query are now RDF::Trine objects |
77
|
|
|
|
|
|
|
(more specifically, RDF::Trine::Node and RDF::Trine::Statement objects). This |
78
|
|
|
|
|
|
|
differes from RDF::Query 1.x where nodes and statements were of the same type |
79
|
|
|
|
|
|
|
as the underlying model (Redland nodes from a Redland model and RDF::Core nodes |
80
|
|
|
|
|
|
|
from an RDF::Core model). |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
In the past, it was possible to execute a query and not know what type of nodes |
83
|
|
|
|
|
|
|
were going to be returned, leading to overly verbose code that required |
84
|
|
|
|
|
|
|
examining all nodes and statements with the bridge object. This new API brings |
85
|
|
|
|
|
|
|
consistency to both the execution model and client code, greatly simplifying |
86
|
|
|
|
|
|
|
interaction with query results. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=item Binding Result Values |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
Binding result values returned by calling C<< $iterator->next >> are now HASH |
91
|
|
|
|
|
|
|
references (instead of ARRAY references), keyed by variable name. Where prior |
92
|
|
|
|
|
|
|
code might use this code (modulo model definition and namespace declarations): |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
my $sparql = 'SELECT ?name ?homepage WHERE { [ foaf:name ?name ; foaf:homepage ?homepage ] }'; |
95
|
|
|
|
|
|
|
my $query = RDF::Query->new( $sparql ); |
96
|
|
|
|
|
|
|
my $iterator = $query->execute( $model ); |
97
|
|
|
|
|
|
|
while (my $row = $iterator->()) { |
98
|
|
|
|
|
|
|
my ($name, $homepage) = @$row; |
99
|
|
|
|
|
|
|
# ... |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
New code using RDF::Query 2.000 and later should instead use: |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
my $sparql = 'SELECT ?name ?homepage WHERE { [ foaf:name ?name ; foaf:homepage ?homepage ] }'; |
105
|
|
|
|
|
|
|
my $query = RDF::Query->new( $sparql ); |
106
|
|
|
|
|
|
|
my $iterator = $query->execute( $model ); |
107
|
|
|
|
|
|
|
while (my $row = $iterator->next) { |
108
|
|
|
|
|
|
|
my $name = $row->{ name }; |
109
|
|
|
|
|
|
|
my $homepage = $row->{ homepage }; |
110
|
|
|
|
|
|
|
# ... |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
(Also notice the new method calling syntax for retrieving rows.) |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=back |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=cut |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
package RDF::Query; |
120
|
|
|
|
|
|
|
|
121
|
35
|
|
|
35
|
|
1989139
|
use strict; |
|
35
|
|
|
|
|
72
|
|
|
35
|
|
|
|
|
865
|
|
122
|
35
|
|
|
35
|
|
172
|
use warnings; |
|
35
|
|
|
|
|
60
|
|
|
35
|
|
|
|
|
894
|
|
123
|
35
|
|
|
35
|
|
164
|
no warnings 'redefine'; |
|
35
|
|
|
|
|
64
|
|
|
35
|
|
|
|
|
1181
|
|
124
|
35
|
|
|
35
|
|
179
|
use Carp qw(carp croak confess); |
|
35
|
|
|
|
|
79
|
|
|
35
|
|
|
|
|
2342
|
|
125
|
|
|
|
|
|
|
|
126
|
35
|
|
|
35
|
|
33034
|
use Data::Dumper; |
|
35
|
|
|
|
|
305107
|
|
|
35
|
|
|
|
|
2371
|
|
127
|
35
|
|
|
35
|
|
33207
|
use LWP::UserAgent; |
|
35
|
|
|
|
|
1518307
|
|
|
35
|
|
|
|
|
1208
|
|
128
|
35
|
|
|
35
|
|
33283
|
use I18N::LangTags; |
|
35
|
|
|
|
|
108559
|
|
|
35
|
|
|
|
|
2140
|
|
129
|
35
|
|
|
35
|
|
227
|
use List::Util qw(first); |
|
35
|
|
|
|
|
70
|
|
|
35
|
|
|
|
|
3736
|
|
130
|
35
|
|
|
35
|
|
187
|
use Scalar::Util qw(blessed reftype looks_like_number); |
|
35
|
|
|
|
|
71
|
|
|
35
|
|
|
|
|
2732
|
|
131
|
35
|
|
|
35
|
|
27645
|
use DateTime::Format::W3CDTF; |
|
35
|
|
|
|
|
5264775
|
|
|
35
|
|
|
|
|
1414
|
|
132
|
|
|
|
|
|
|
|
133
|
35
|
|
|
35
|
|
42905
|
use Log::Log4perl qw(:easy); |
|
35
|
|
|
|
|
1764754
|
|
|
35
|
|
|
|
|
220
|
|
134
|
|
|
|
|
|
|
if (! Log::Log4perl::initialized()) { |
135
|
|
|
|
|
|
|
Log::Log4perl->easy_init($ERROR); |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
35
|
|
|
35
|
|
21082
|
no warnings 'numeric'; |
|
35
|
|
|
|
|
73
|
|
|
35
|
|
|
|
|
1261
|
|
139
|
35
|
|
|
35
|
|
25857
|
use RDF::Trine 1.004; |
|
35
|
|
|
|
|
40642347
|
|
|
35
|
|
|
|
|
2202
|
|
140
|
|
|
|
|
|
|
require RDF::Query::Functions; # (needs to happen at runtime because some of the functions rely on RDF::Query being fully loaded (to call add_hook(), for example)) |
141
|
|
|
|
|
|
|
# all the built-in functions including: |
142
|
|
|
|
|
|
|
# datatype casting, language ops, logical ops, |
143
|
|
|
|
|
|
|
# numeric ops, datetime ops, and node type testing |
144
|
|
|
|
|
|
|
# also, custom functions including: |
145
|
|
|
|
|
|
|
# jena:sha1sum, jena:now, jena:langeq, jena:listMember |
146
|
|
|
|
|
|
|
# ldodds:Distance, kasei:warn |
147
|
35
|
|
|
35
|
|
20293
|
use RDF::Query::Expression; |
|
35
|
|
|
|
|
149
|
|
|
35
|
|
|
|
|
1550
|
|
148
|
35
|
|
|
35
|
|
205
|
use RDF::Query::Algebra; |
|
35
|
|
|
|
|
72
|
|
|
35
|
|
|
|
|
1365
|
|
149
|
35
|
|
|
35
|
|
19847
|
use RDF::Query::Node qw(iri); |
|
35
|
|
|
|
|
142
|
|
|
35
|
|
|
|
|
2086
|
|
150
|
35
|
|
|
35
|
|
26088
|
use RDF::Query::Parser::RDQL; |
|
35
|
|
|
|
|
153
|
|
|
35
|
|
|
|
|
1192
|
|
151
|
35
|
|
|
35
|
|
222
|
use RDF::Query::Parser::SPARQL; |
|
35
|
|
|
|
|
75
|
|
|
35
|
|
|
|
|
869
|
|
152
|
35
|
|
|
35
|
|
42569
|
use RDF::Query::Parser::SPARQL11; |
|
35
|
|
|
|
|
169
|
|
|
35
|
|
|
|
|
1544
|
|
153
|
35
|
|
|
35
|
|
30703
|
use RDF::Query::Compiler::SQL; |
|
35
|
|
|
|
|
172
|
|
|
35
|
|
|
|
|
1294
|
|
154
|
35
|
|
|
35
|
|
218
|
use RDF::Query::Error qw(:try); |
|
35
|
|
|
|
|
86
|
|
|
35
|
|
|
|
|
289
|
|
155
|
35
|
|
|
35
|
|
32188
|
use RDF::Query::Plan; |
|
35
|
|
|
|
|
151
|
|
|
35
|
|
|
|
|
2386
|
|
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
###################################################################### |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
our ($VERSION, $DEFAULT_PARSER); |
160
|
|
|
|
|
|
|
BEGIN { |
161
|
35
|
|
|
35
|
|
104
|
$VERSION = '2.915_01'; |
162
|
35
|
|
|
|
|
4412
|
$DEFAULT_PARSER = 'sparql11'; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
###################################################################### |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head1 METHODS |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=over 4 |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=item C<< new ( $query, \%options ) >> |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
Returns a new RDF::Query object for the specified C<$query>. |
175
|
|
|
|
|
|
|
The query language defaults to SPARQL 1.1, but may be set specifically |
176
|
|
|
|
|
|
|
with the appropriate C<< %options >> value. Valid C<< %options >> are: |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
* lang |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
Specifies the query language. Acceptable values are 'sparql11', 'sparql', or 'rdql'. |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
* base_uri |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Specifies the base URI used in parsing the query. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
* update |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
A boolean value indicating whether update operations are allowed during query execution. |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
* load_data |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
A boolean value indicating whether URIs used in SPARQL FROM and FROM NAMED clauses |
193
|
|
|
|
|
|
|
should be dereferenced and the resulting RDF content used to construct the dataset |
194
|
|
|
|
|
|
|
against which the query is run. |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=cut |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub new { |
199
|
207
|
|
|
207
|
1
|
10575340
|
my $class = shift; |
200
|
207
|
|
|
|
|
489
|
my $query = shift; |
201
|
|
|
|
|
|
|
|
202
|
207
|
|
|
|
|
465
|
my ($base_uri, $languri, $lang, %options); |
203
|
207
|
100
|
100
|
|
|
1776
|
if (@_ and ref($_[0])) { |
204
|
43
|
|
|
|
|
92
|
%options = %{ shift() }; |
|
43
|
|
|
|
|
231
|
|
205
|
43
|
|
|
|
|
129
|
$lang = delete $options{ lang }; |
206
|
43
|
|
33
|
|
|
228
|
$base_uri = $options{ base_uri } || $options{ base } ; |
207
|
43
|
|
|
|
|
94
|
delete $options{ base_uri }; |
208
|
43
|
|
|
|
|
93
|
delete $options{ base }; |
209
|
|
|
|
|
|
|
} else { |
210
|
164
|
|
|
|
|
663
|
($base_uri, $languri, $lang, %options) = @_; |
211
|
|
|
|
|
|
|
} |
212
|
207
|
|
|
|
|
1144
|
$class->clear_error; |
213
|
|
|
|
|
|
|
|
214
|
207
|
|
|
|
|
1204
|
my $l = Log::Log4perl->get_logger("rdf.query"); |
215
|
35
|
|
|
35
|
|
266
|
no warnings 'uninitialized'; |
|
35
|
|
|
|
|
86
|
|
|
35
|
|
|
|
|
152320
|
|
216
|
|
|
|
|
|
|
|
217
|
207
|
|
|
|
|
16537
|
my %names = ( |
218
|
|
|
|
|
|
|
rdql => 'RDF::Query::Parser::RDQL', |
219
|
|
|
|
|
|
|
sparql => 'RDF::Query::Parser::SPARQL', |
220
|
|
|
|
|
|
|
sparql11 => 'RDF::Query::Parser::SPARQL11', |
221
|
|
|
|
|
|
|
); |
222
|
207
|
|
|
|
|
2050
|
my %uris = ( |
223
|
|
|
|
|
|
|
'http://jena.hpl.hp.com/2003/07/query/RDQL' => 'RDF::Query::Parser::RDQL', |
224
|
|
|
|
|
|
|
'http://www.w3.org/TR/rdf-sparql-query/' => 'RDF::Query::Parser::SPARQL', |
225
|
|
|
|
|
|
|
'http://www.w3.org/ns/sparql-service-description#SPARQL10Query' => 'RDF::Query::Parser::SPARQL', |
226
|
|
|
|
|
|
|
'http://www.w3.org/ns/sparql-service-description#SPARQL11Query' => 'RDF::Query::Parser::SPARQL11', |
227
|
|
|
|
|
|
|
'http://www.w3.org/ns/sparql-service-description#SPARQL11Update' => 'RDF::Query::Parser::SPARQL11', |
228
|
|
|
|
|
|
|
); |
229
|
|
|
|
|
|
|
|
230
|
207
|
50
|
|
|
|
700
|
if ($base_uri) { |
231
|
0
|
|
|
|
|
0
|
$base_uri = RDF::Query::Node::Resource->new( $base_uri ); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
207
|
|
|
|
|
380
|
my %pargs; |
235
|
207
|
50
|
|
|
|
817
|
if ($options{canonicalize}) { |
236
|
0
|
|
|
|
|
0
|
$pargs{canonicalize} = 1; |
237
|
|
|
|
|
|
|
} |
238
|
207
|
100
|
|
|
|
718
|
my $update = ((delete $options{update}) ? 1 : 0); |
239
|
207
|
|
66
|
|
|
1031
|
my $pclass = $names{ $lang } || $uris{ $languri } || $names{ $DEFAULT_PARSER }; |
240
|
207
|
|
|
|
|
1728
|
my $parser = $pclass->new( %pargs ); |
241
|
207
|
|
|
|
|
425
|
my $parsed; |
242
|
|
|
|
|
|
|
|
243
|
207
|
50
|
33
|
|
|
947
|
if (ref($query) and $query->isa('RDF::Query::Algebra')) { |
244
|
0
|
|
|
|
|
0
|
my $method = 'SELECT'; |
245
|
0
|
0
|
|
|
|
0
|
$method = 'ASK' if ($query->isa('RDF::Query::Algebra::Ask')); |
246
|
0
|
0
|
|
|
|
0
|
$method = 'CONSTRUCT' if ($query->isa('RDF::Query::Algebra::Construct')); |
247
|
0
|
|
|
|
|
0
|
my @vars = map { RDF::Query::Node::Variable->new($_) } _uniq($query->potentially_bound); |
|
0
|
|
|
|
|
0
|
|
248
|
0
|
0
|
|
|
|
0
|
if ($method eq 'SELECT') { |
249
|
0
|
0
|
|
|
|
0
|
unless ($query->isa('RDF::Query::Algebra::Project')) { |
250
|
0
|
|
|
|
|
0
|
$query = RDF::Query::Algebra::Project->new($query, \@vars); |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
$parsed = { |
254
|
0
|
|
|
|
|
0
|
method => $method, |
255
|
|
|
|
|
|
|
triples => [$query], |
256
|
|
|
|
|
|
|
sources => [], |
257
|
|
|
|
|
|
|
base => $base_uri, |
258
|
|
|
|
|
|
|
options => {}, |
259
|
|
|
|
|
|
|
star => 0, |
260
|
|
|
|
|
|
|
variables => \@vars, |
261
|
|
|
|
|
|
|
}; |
262
|
0
|
|
|
|
|
0
|
$query = $query->as_sparql; |
263
|
|
|
|
|
|
|
} else { |
264
|
207
|
|
|
|
|
965
|
$parsed = $parser->parse( $query, $base_uri, $update ); |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
207
|
|
|
|
|
1429
|
my $self = $class->_new( |
268
|
|
|
|
|
|
|
base_uri => $base_uri, |
269
|
|
|
|
|
|
|
parser => $parser, |
270
|
|
|
|
|
|
|
parsed => $parsed, |
271
|
|
|
|
|
|
|
query_string => $query, |
272
|
|
|
|
|
|
|
update => $update, |
273
|
|
|
|
|
|
|
options => { %options }, |
274
|
|
|
|
|
|
|
); |
275
|
207
|
50
|
|
|
|
1670
|
if (exists $options{load_data}) { |
|
|
100
|
|
|
|
|
|
276
|
0
|
|
|
|
|
0
|
$self->{load_data} = delete $options{load_data}; |
277
|
|
|
|
|
|
|
} elsif ($pclass =~ /^RDF::Query::Parser::(RDQL|SPARQL)$/) { |
278
|
106
|
|
|
|
|
402
|
$self->{load_data} = 1; |
279
|
|
|
|
|
|
|
} else { |
280
|
101
|
|
|
|
|
287
|
$self->{load_data} = 0; |
281
|
|
|
|
|
|
|
} |
282
|
207
|
100
|
|
|
|
706
|
unless ($parsed->{'triples'}) { |
283
|
2
|
|
|
|
|
13
|
$class->set_error( $parser->error ); |
284
|
2
|
|
|
|
|
7
|
$l->debug($parser->error); |
285
|
2
|
|
|
|
|
30
|
return; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
205
|
50
|
|
|
|
672
|
if (defined $options{defines}) { |
289
|
0
|
|
|
|
|
0
|
@{ $self->{options} }{ keys %{ $options{defines} } } = values %{ delete $options{defines} }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
205
|
50
|
|
|
|
603
|
if ($options{logger}) { |
293
|
0
|
|
|
|
|
0
|
$l->debug("got external logger"); |
294
|
0
|
|
|
|
|
0
|
$self->{logger} = delete $options{logger}; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
205
|
50
|
|
|
|
612
|
if (my $opt = delete $options{optimize}) { |
298
|
0
|
|
|
|
|
0
|
$l->debug("got optimization flag: $opt"); |
299
|
0
|
|
|
|
|
0
|
$self->{optimize} = $opt; |
300
|
|
|
|
|
|
|
} else { |
301
|
205
|
|
|
|
|
728
|
$self->{optimize} = 0; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
205
|
50
|
|
|
|
647
|
if (my $opt = delete $options{force_no_optimization}) { |
305
|
0
|
|
|
|
|
0
|
$l->debug("got force_no_optimization flag"); |
306
|
0
|
|
|
|
|
0
|
$self->{force_no_optimization} = 1; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
205
|
50
|
|
|
|
631
|
if (my $time = delete $options{optimistic_threshold_time}) { |
310
|
0
|
|
|
|
|
0
|
$l->debug("got optimistic_threshold_time flag"); |
311
|
0
|
|
|
|
|
0
|
$self->{optimistic_threshold_time} = $time; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# add rdf as a default namespace to RDQL queries |
315
|
205
|
100
|
|
|
|
623
|
if ($pclass eq 'RDF::Query::Parser::RDQL') { |
316
|
17
|
|
|
|
|
67
|
$self->{parsed}{namespaces}{rdf} = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; |
317
|
|
|
|
|
|
|
} |
318
|
205
|
|
|
|
|
1716
|
return $self; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub _new { |
322
|
208
|
|
|
208
|
|
432
|
my $class = shift; |
323
|
208
|
|
|
|
|
1531
|
my $self = bless( { @_ }, $class ); |
324
|
208
|
|
|
|
|
544
|
return $self; |
325
|
|
|
|
|
|
|
} |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
=item C<< get ( $model ) >> |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
Executes the query using the specified model, and returns the first matching row as a LIST of values. |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=cut |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub get { |
334
|
18
|
|
|
18
|
1
|
433
|
my $self = shift; |
335
|
18
|
|
|
|
|
92
|
my $stream = $self->execute( @_ ); |
336
|
18
|
|
|
|
|
104
|
my $row = $stream->next; |
337
|
18
|
100
|
|
|
|
331
|
if (ref($row)) { |
338
|
17
|
|
|
|
|
61
|
return @{ $row }{ $self->variables }; |
|
17
|
|
|
|
|
134
|
|
339
|
|
|
|
|
|
|
} else { |
340
|
1
|
|
|
|
|
7
|
return undef; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=item C<< prepare ( $model ) >> |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
Prepares the query, constructing a query execution plan, and returns a list |
347
|
|
|
|
|
|
|
containing ($plan, $context). To execute the plan, call |
348
|
|
|
|
|
|
|
C<< execute_plan( $plan, $context ) >>. |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=cut |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
sub prepare { |
353
|
158
|
|
|
158
|
1
|
996
|
my $self = shift; |
354
|
158
|
|
|
|
|
270
|
my $_model = shift; |
355
|
158
|
|
|
|
|
344
|
my %args = @_; |
356
|
158
|
|
|
|
|
625
|
my $l = Log::Log4perl->get_logger("rdf.query"); |
357
|
|
|
|
|
|
|
|
358
|
158
|
|
|
|
|
3324
|
$self->{_query_cache} = {}; # a new scratch hash for each execution. |
359
|
158
|
|
|
|
|
287
|
my %bound; |
360
|
158
|
100
|
|
|
|
498
|
if ($args{ 'bind' }) { |
361
|
1
|
|
|
|
|
3
|
%bound = %{ $args{ 'bind' } }; |
|
1
|
|
|
|
|
5
|
|
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
158
|
|
|
|
|
247
|
my $delegate; |
365
|
158
|
50
|
|
|
|
525
|
if (defined $args{ 'delegate' }) { |
366
|
0
|
|
|
|
|
0
|
$delegate = delete $args{ 'delegate' }; |
367
|
0
|
0
|
0
|
|
|
0
|
if ($delegate and not blessed($delegate)) { |
368
|
0
|
|
|
|
|
0
|
$delegate = $delegate->new(); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
} |
371
|
158
|
50
|
|
|
|
519
|
my $errors = ($args{ 'strict_errors' }) ? 1 : 0; |
372
|
158
|
|
|
|
|
306
|
my $parsed = $self->{parsed}; |
373
|
158
|
|
|
|
|
618
|
my @vars = $self->variables( $parsed ); |
374
|
|
|
|
|
|
|
|
375
|
158
|
|
|
|
|
556
|
local($self->{model}) = $self->{model}; |
376
|
158
|
|
33
|
|
|
1011
|
my $model = $self->{model} || $self->get_model( $_model, %args ); |
377
|
158
|
50
|
|
|
|
426
|
if ($model) { |
378
|
158
|
|
|
|
|
584
|
$self->model( $model ); |
379
|
158
|
|
|
|
|
821
|
$l->debug("got model $model"); |
380
|
|
|
|
|
|
|
} else { |
381
|
0
|
|
|
|
|
0
|
throw RDF::Query::Error::ModelError ( -text => "Could not create a model object." ); |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
158
|
100
|
|
|
|
1551
|
if ($self->{load_data}) { |
385
|
100
|
|
|
|
|
481
|
$l->trace("loading data"); |
386
|
100
|
|
|
|
|
859
|
$self->load_data(); |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
|
389
|
158
|
|
|
|
|
441
|
$model = $self->model(); # reload the model object, because load_data might have changed it. |
390
|
|
|
|
|
|
|
|
391
|
158
|
100
|
|
|
|
1865
|
my $dataset = ($model->isa('RDF::Trine::Model::Dataset')) ? $model : RDF::Trine::Model::Dataset->new($model); |
392
|
|
|
|
|
|
|
|
393
|
158
|
|
|
|
|
1671
|
$l->trace("constructing ExecutionContext"); |
394
|
|
|
|
|
|
|
my $context = RDF::Query::ExecutionContext->new( |
395
|
|
|
|
|
|
|
bound => \%bound, |
396
|
|
|
|
|
|
|
model => $dataset, |
397
|
|
|
|
|
|
|
query => $self, |
398
|
|
|
|
|
|
|
base_uri => $parsed->{base_uri}, |
399
|
|
|
|
|
|
|
ns => $parsed->{namespaces}, |
400
|
|
|
|
|
|
|
logger => $self->logger, |
401
|
|
|
|
|
|
|
optimize => $self->{optimize}, |
402
|
|
|
|
|
|
|
force_no_optimization => $self->{force_no_optimization}, |
403
|
|
|
|
|
|
|
optimistic_threshold_time => $self->{optimistic_threshold_time} || 0, |
404
|
|
|
|
|
|
|
requested_variables => \@vars, |
405
|
|
|
|
|
|
|
strict_errors => $errors, |
406
|
|
|
|
|
|
|
options => $self->{options}, |
407
|
158
|
|
50
|
|
|
1915
|
delegate => $delegate, |
408
|
|
|
|
|
|
|
); |
409
|
158
|
|
|
|
|
529
|
$self->{model} = $model; |
410
|
|
|
|
|
|
|
|
411
|
158
|
|
|
|
|
526
|
$l->trace("getting QEP..."); |
412
|
158
|
100
|
|
|
|
1031
|
my %plan_args = %{ $args{ planner_args } || {} }; |
|
158
|
|
|
|
|
1070
|
|
413
|
158
|
|
|
|
|
826
|
my $plan = $self->query_plan( $context, %plan_args ); |
414
|
158
|
|
|
|
|
559
|
$l->trace("-> done."); |
415
|
|
|
|
|
|
|
|
416
|
158
|
50
|
|
|
|
1296
|
unless ($plan) { |
417
|
0
|
|
|
|
|
0
|
throw RDF::Query::Error::CompilationError -text => "Query didn't produce a valid execution plan"; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
158
|
|
|
|
|
823
|
return ($plan, $context); |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=item C<execute ( $model, %args )> |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
Executes the query using the specified RDF C<< $model >>. If called in a list |
426
|
|
|
|
|
|
|
context, returns an array of rows, otherwise returns an L<RDF::Trine::Iterator> |
427
|
|
|
|
|
|
|
object. The iterator returned may be an instance of several subclasses of |
428
|
|
|
|
|
|
|
L<RDF::Trine::Iterator>: |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
* A L<RDF::Trine::Iterator::Bindings> object is returned for query forms producing variable binding results (SELECT queries). |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
* A L<RDF::Trine::Iterator::Graph> object is returned for query forms producing in an RDF graph result (DESCRIBE and CONSTRUCT queries). |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
* A L<RDF::Trine::Iterator::Boolean> object is returned for query forms producing a true/false result (ASK queries). |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=cut |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
sub execute { |
439
|
138
|
|
|
138
|
1
|
7778
|
my $self = shift; |
440
|
138
|
|
|
|
|
259
|
my $model = shift; |
441
|
138
|
|
|
|
|
332
|
my %args = @_; |
442
|
138
|
|
|
|
|
742
|
my $l = Log::Log4perl->get_logger("rdf.query"); |
443
|
138
|
|
100
|
|
|
4346
|
$l->debug("executing query with model " . ($model or '')); |
444
|
|
|
|
|
|
|
|
445
|
138
|
|
|
|
|
1410
|
my $lang_iri = ''; |
446
|
138
|
|
|
|
|
325
|
my $parser = $self->{parser}; |
447
|
138
|
|
|
|
|
216
|
my $name; |
448
|
138
|
100
|
|
|
|
1462
|
if ($parser->isa('RDF::Query::Parser::SPARQL11')) { |
|
|
100
|
|
|
|
|
|
449
|
42
|
100
|
|
|
|
185
|
if ($self->is_update) { |
450
|
5
|
|
|
|
|
12
|
$name = 'SPARQL 1.1 Update'; |
451
|
5
|
|
|
|
|
10
|
$lang_iri = 'http://www.w3.org/ns/sparql-service-description#SPARQL11Update'; |
452
|
|
|
|
|
|
|
} else { |
453
|
37
|
|
|
|
|
81
|
$name = 'SPARQL 1.1 Query'; |
454
|
37
|
|
|
|
|
83
|
$lang_iri = 'http://www.w3.org/ns/sparql-service-description#SPARQL11Query'; |
455
|
|
|
|
|
|
|
} |
456
|
|
|
|
|
|
|
} elsif ($parser->isa('RDF::Query::Parser::SPARQL')) { |
457
|
83
|
|
|
|
|
174
|
$name = 'SPARQL 1.0 Query'; |
458
|
83
|
|
|
|
|
172
|
$lang_iri = 'http://www.w3.org/ns/sparql-service-description#SPARQL10Query'; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
|
461
|
138
|
|
|
|
|
514
|
local($self->{model}) = $self->{model}; |
462
|
|
|
|
|
|
|
# warn "model: $self->{model}"; |
463
|
|
|
|
|
|
|
# warn "passthrough checking if model supports $lang_iri\n"; |
464
|
138
|
50
|
33
|
|
|
687
|
if ($self->{options}{allow_passthrough} and $model->supports($lang_iri)) { |
465
|
0
|
|
|
|
|
0
|
$l->info("delegating $name execution to the underlying model"); |
466
|
0
|
|
|
|
|
0
|
return $model->get_sparql( $self->{query_string} ); |
467
|
|
|
|
|
|
|
} else { |
468
|
138
|
|
|
|
|
678
|
my ($plan, $context) = $self->prepare( $model, %args ); |
469
|
138
|
50
|
|
|
|
525
|
if ($l->is_trace) { |
470
|
0
|
|
|
|
|
0
|
$l->trace(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); |
471
|
0
|
|
|
|
|
0
|
$l->trace($self->as_sparql); |
472
|
0
|
|
|
|
|
0
|
$l->trace(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); |
473
|
|
|
|
|
|
|
} |
474
|
138
|
|
|
|
|
1344
|
return $self->execute_plan( $plan, $context ); |
475
|
|
|
|
|
|
|
} |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=item C<< execute_plan ( $plan, $context ) >> |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
Executes the query plan generated by the C<<prepare>> method using the supplied |
481
|
|
|
|
|
|
|
L<RDF::Query::ExecutionContext> object. Return value(s) are the same as for the |
482
|
|
|
|
|
|
|
C<<execute>> method. |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=cut |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
sub execute_plan { |
487
|
157
|
|
|
157
|
1
|
333
|
my $self = shift; |
488
|
157
|
|
|
|
|
261
|
my $plan = shift; |
489
|
157
|
|
|
|
|
253
|
my $context = shift; |
490
|
157
|
|
|
|
|
557
|
my $model = $context->model; |
491
|
157
|
|
|
|
|
392
|
my $parsed = $self->{parsed}; |
492
|
157
|
|
|
|
|
568
|
my @vars = $self->variables( $parsed ); |
493
|
|
|
|
|
|
|
|
494
|
157
|
|
|
|
|
598
|
my $l = Log::Log4perl->get_logger("rdf.query"); |
495
|
|
|
|
|
|
|
|
496
|
157
|
|
|
|
|
3160
|
my $pattern = $self->pattern; |
497
|
|
|
|
|
|
|
# $l->trace("calling fixup()"); |
498
|
|
|
|
|
|
|
# my $cpattern = $self->fixup(); |
499
|
|
|
|
|
|
|
|
500
|
157
|
|
|
|
|
884
|
my @funcs = $pattern->referenced_functions; |
501
|
157
|
|
|
|
|
391
|
foreach my $f (@funcs) { |
502
|
32
|
|
|
|
|
133
|
$self->run_hook( 'http://kasei.us/code/rdf-query/hooks/function_init', $f ); |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
# RUN THE QUERY! |
506
|
|
|
|
|
|
|
|
507
|
157
|
|
|
|
|
629
|
$l->debug("executing the graph pattern"); |
508
|
|
|
|
|
|
|
|
509
|
157
|
|
50
|
|
|
1810
|
my $options = $parsed->{options} || {}; |
510
|
157
|
50
|
|
|
|
540
|
if ($self->{options}{plan}) { |
511
|
0
|
|
|
|
|
0
|
warn $plan->sse({}, ''); |
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
157
|
|
|
|
|
763
|
$plan->execute( $context ); |
515
|
157
|
|
|
|
|
826
|
my $stream = $plan->as_iterator( $context ); |
516
|
|
|
|
|
|
|
|
517
|
157
|
100
|
|
|
|
911
|
if ($parsed->{'method'} eq 'DESCRIBE') { |
|
|
100
|
|
|
|
|
|
518
|
4
|
|
|
|
|
19
|
$stream = $self->describe( $stream, $context ); |
519
|
|
|
|
|
|
|
} elsif ($parsed->{'method'} eq 'ASK') { |
520
|
8
|
|
|
|
|
31
|
$stream = $self->ask( $stream, $context ); |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
157
|
|
|
|
|
1004
|
$l->debug("going to call post-execute hook"); |
524
|
157
|
|
|
|
|
1563
|
$self->run_hook( 'http://kasei.us/code/rdf-query/hooks/post-execute', $model, $stream ); |
525
|
|
|
|
|
|
|
|
526
|
157
|
100
|
|
|
|
397
|
if (wantarray) { |
527
|
19
|
|
|
|
|
99
|
return $stream->get_all(); |
528
|
|
|
|
|
|
|
} else { |
529
|
138
|
|
|
|
|
1841
|
return $stream; |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=item C<< prepare_with_named_graphs ( $model, @uris ) >> |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=cut |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub prepare_with_named_graphs { |
538
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
539
|
0
|
|
|
|
|
0
|
my $_model = shift; |
540
|
0
|
|
|
|
|
0
|
my @graphs = @_; |
541
|
0
|
|
|
|
|
0
|
my $l = Log::Log4perl->get_logger("rdf.query"); |
542
|
|
|
|
|
|
|
# $self->{model} = $model; |
543
|
0
|
|
|
|
|
0
|
my $model = $self->get_model( $_model ); |
544
|
0
|
0
|
|
|
|
0
|
if ($model) { |
545
|
0
|
|
|
|
|
0
|
$self->model( $model ); |
546
|
|
|
|
|
|
|
} else { |
547
|
0
|
|
|
|
|
0
|
throw RDF::Query::Error::ModelError ( -text => "Could not create a model object." ); |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
0
|
|
|
|
|
0
|
foreach my $gdata (@graphs) { |
551
|
0
|
0
|
|
|
|
0
|
my $url = (blessed($gdata)) ? $gdata->uri_value : $gdata; |
552
|
0
|
|
|
|
|
0
|
$l->debug("-> adding graph data $url"); |
553
|
0
|
|
|
|
|
0
|
$self->parse_url( $url, 1 ); |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
|
556
|
0
|
|
|
|
|
0
|
return $self->prepare( $model ); |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=item C<< execute_with_named_graphs ( $model, @uris ) >> |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
Executes the query using the specified RDF C<< $model >>, loading the contents |
562
|
|
|
|
|
|
|
of the specified C<@uris> into named graphs immediately prior to matching the |
563
|
|
|
|
|
|
|
query. Otherwise, acts just like C<< execute >>. |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
=cut |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
sub execute_with_named_graphs { |
568
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
569
|
0
|
|
|
|
|
0
|
my $_model = shift; |
570
|
0
|
|
|
|
|
0
|
my @graphs; |
571
|
|
|
|
|
|
|
my @options; |
572
|
0
|
0
|
|
|
|
0
|
if (scalar(@_)) { |
573
|
0
|
0
|
0
|
|
|
0
|
if (not(blessed($_[0])) and reftype($_[0]) eq 'ARRAY') { |
574
|
0
|
|
|
|
|
0
|
@graphs = @{ shift(@_) }; |
|
0
|
|
|
|
|
0
|
|
575
|
0
|
|
|
|
|
0
|
@options = @_; |
576
|
|
|
|
|
|
|
} else { |
577
|
0
|
|
|
|
|
0
|
@graphs = @_; |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
0
|
|
|
|
|
0
|
my ($plan, $ctx) = $self->prepare_with_named_graphs( $_model, @graphs ); |
582
|
0
|
|
|
|
|
0
|
return $self->execute_plan( $plan, $ctx ); |
583
|
|
|
|
|
|
|
} |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
=begin private |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
=item C<< query_plan ( $execution_context ) >> |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
Returns a RDF::Query::Plan object that is (hopefully) the optimal QEP for the |
590
|
|
|
|
|
|
|
current query. |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=end private |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
=cut |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
sub query_plan { |
597
|
158
|
|
|
158
|
1
|
303
|
my $self = shift; |
598
|
158
|
|
|
|
|
276
|
my $context = shift; |
599
|
158
|
|
|
|
|
313
|
my %args = @_; |
600
|
158
|
|
|
|
|
356
|
my $parsed = $self->{parsed}; |
601
|
|
|
|
|
|
|
|
602
|
158
|
|
|
|
|
719
|
my $bound = $context->bound; |
603
|
158
|
|
|
|
|
333
|
my @bkeys = keys %{ $bound }; |
|
158
|
|
|
|
|
436
|
|
604
|
158
|
|
|
|
|
619
|
my $model = $context->model; |
605
|
|
|
|
|
|
|
|
606
|
158
|
100
|
|
|
|
533
|
unless ($self->{update}) { |
607
|
148
|
50
|
33
|
|
|
688
|
if (not exists $self->{options}{'rdf.query.plan.delegate'} or $self->{options}{'rdf.query.plan.delegate'}) { |
608
|
|
|
|
|
|
|
my $delegate_key = $self->{update} |
609
|
148
|
50
|
|
|
|
465
|
? 'http://www.w3.org/ns/sparql-service-description#SPARQL11Update' |
610
|
|
|
|
|
|
|
: "http://www.w3.org/ns/sparql-service-description#SPARQL10Query"; # TODO: need to determine if the query is only 1.0, and if so, check for 1.0 support. otherwise check for 1.1 support |
611
|
148
|
50
|
66
|
|
|
974
|
if (scalar(@bkeys) == 0 and $model->supports($delegate_key)) { |
612
|
|
|
|
|
|
|
my $plan = RDF::Query::Plan::Iterator->new( sub { |
613
|
0
|
|
|
0
|
|
0
|
my $context = shift; |
614
|
0
|
|
|
|
|
0
|
my $model = $context->model; |
615
|
0
|
|
|
|
|
0
|
my $iter = $model->get_sparql( $self->{query_string} ); |
616
|
0
|
|
|
|
|
0
|
return $iter; |
617
|
0
|
|
|
|
|
0
|
} ); |
618
|
0
|
|
|
|
|
0
|
return $plan; |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
|
623
|
158
|
|
|
|
|
3924
|
my %constant_plan; |
624
|
158
|
100
|
|
|
|
571
|
if (my $b = $self->{parsed}{bindings}) { |
625
|
3
|
|
|
|
|
10
|
my $vars = $b->{vars}; |
626
|
3
|
|
|
|
|
7
|
my $values = $b->{terms}; |
627
|
3
|
|
|
|
|
5
|
my @names = map { $_->name } @{ $vars }; |
|
5
|
|
|
|
|
22
|
|
|
3
|
|
|
|
|
7
|
|
628
|
3
|
|
|
|
|
17
|
my @constants; |
629
|
3
|
|
|
|
|
5
|
while (my $values = shift(@{ $b->{terms} })) { |
|
7
|
|
|
|
|
24
|
|
630
|
4
|
|
|
|
|
6
|
my %bound; |
631
|
|
|
|
|
|
|
# @bound{ @names } = @{ $values }; |
632
|
4
|
|
|
|
|
10
|
foreach my $i (0 .. $#names) { |
633
|
6
|
|
|
|
|
14
|
my $k = $names[$i]; |
634
|
6
|
|
|
|
|
9
|
my $v = $values->[$i]; |
635
|
6
|
100
|
|
|
|
14
|
next unless defined($v); |
636
|
5
|
|
|
|
|
14
|
$bound{ $k } = $v; |
637
|
|
|
|
|
|
|
} |
638
|
4
|
|
|
|
|
22
|
my $bound = RDF::Query::VariableBindings->new( \%bound ); |
639
|
4
|
|
|
|
|
11
|
push(@constants, $bound); |
640
|
|
|
|
|
|
|
} |
641
|
3
|
|
|
|
|
27
|
my $constant_plan = RDF::Query::Plan::Constant->new( @constants ); |
642
|
3
|
|
|
|
|
14
|
%constant_plan = ( constants => [ $constant_plan ] ); |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
|
645
|
158
|
|
|
|
|
599
|
my $algebra = $self->pattern; |
646
|
158
|
|
|
|
|
568
|
my $pclass = $self->plan_class; |
647
|
158
|
|
|
|
|
1231
|
my @plans = $pclass->generate_plans( $algebra, $context, %args, %constant_plan ); |
648
|
|
|
|
|
|
|
|
649
|
158
|
|
|
|
|
661
|
my $l = Log::Log4perl->get_logger("rdf.query.plan"); |
650
|
158
|
50
|
|
|
|
3481
|
if (wantarray) { |
651
|
0
|
|
|
|
|
0
|
return @plans; |
652
|
|
|
|
|
|
|
} else { |
653
|
158
|
|
|
|
|
315
|
my ($plan) = @plans; # XXX need to figure out what's the 'best' plan here |
654
|
158
|
50
|
|
|
|
617
|
if ($l->is_debug) { |
655
|
0
|
|
|
|
|
0
|
$l->debug("using query plan: " . $plan->sse({}, '')); |
656
|
|
|
|
|
|
|
} |
657
|
158
|
|
|
|
|
1541
|
return $plan; |
658
|
|
|
|
|
|
|
} |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=begin private |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
=item C<< plan_class >> |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
Returns the class name for Plan generation. This method should be overloaded by |
666
|
|
|
|
|
|
|
RDF::Query subclasses if the implementation also provides a subclass of |
667
|
|
|
|
|
|
|
RDF::Query::Plan. |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=end private |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
=cut |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
sub plan_class { |
674
|
158
|
|
|
158
|
1
|
369
|
return 'RDF::Query::Plan'; |
675
|
|
|
|
|
|
|
} |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=begin private |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=item C<< describe ( $iter, $context ) >> |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
Takes a stream of matching statements and constructs a DESCRIBE graph. |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
=end private |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
=cut |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
sub describe { |
688
|
4
|
|
|
4
|
1
|
7
|
my $self = shift; |
689
|
4
|
|
|
|
|
11
|
my $stream = shift; |
690
|
4
|
|
|
|
|
5
|
my $context = shift; |
691
|
4
|
|
|
|
|
15
|
my $model = $context->model; |
692
|
4
|
|
|
|
|
8
|
my @nodes; |
693
|
|
|
|
|
|
|
my %seen; |
694
|
4
|
|
|
|
|
18
|
while (my $row = $stream->next) { |
695
|
7
|
|
|
|
|
11
|
foreach my $v (@{ $self->{parsed}{variables} }) { |
|
7
|
|
|
|
|
22
|
|
696
|
7
|
100
|
|
|
|
34
|
if ($v->isa('RDF::Query::Node::Variable')) { |
|
|
50
|
|
|
|
|
|
697
|
6
|
|
|
|
|
22
|
my $node = $row->{ $v->name }; |
698
|
6
|
50
|
|
|
|
51
|
my $string = blessed($node) ? $node->as_string : ''; |
699
|
6
|
100
|
|
|
|
84
|
push(@nodes, $node) unless ($seen{ $string }++); |
700
|
|
|
|
|
|
|
} elsif ($v->isa('RDF::Query::Node::Resource')) { |
701
|
1
|
50
|
|
|
|
9
|
my $string = blessed($v) ? $v->as_string : ''; |
702
|
1
|
50
|
|
|
|
16
|
push(@nodes, $v) unless ($seen{ $string }++); |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
} |
706
|
|
|
|
|
|
|
|
707
|
4
|
|
|
|
|
77
|
my @streams; |
708
|
4
|
|
|
|
|
14
|
$self->{'describe_nodes'} = []; |
709
|
4
|
|
|
|
|
9
|
foreach my $node (@nodes) { |
710
|
4
|
|
|
|
|
7
|
push(@{ $self->{'describe_nodes'} }, $node); |
|
4
|
|
|
|
|
11
|
|
711
|
4
|
|
|
|
|
31
|
push(@streams, $model->bounded_description( $node )); |
712
|
|
|
|
|
|
|
} |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
my $ret = sub { |
715
|
148
|
|
|
148
|
|
40057
|
while (@streams) { |
716
|
148
|
|
|
|
|
464
|
my $val = $streams[0]->next; |
717
|
148
|
100
|
|
|
|
95048
|
if (defined $val) { |
718
|
144
|
|
|
|
|
332
|
return $val; |
719
|
|
|
|
|
|
|
} else { |
720
|
4
|
|
|
|
|
7
|
shift(@streams); |
721
|
4
|
50
|
|
|
|
78
|
return undef if (not @streams); |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
} |
724
|
4
|
|
|
|
|
255
|
}; |
725
|
4
|
|
|
|
|
17
|
return RDF::Trine::Iterator::Graph->new( $ret ); |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=begin private |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
=item C<ask ( $iter, $context )> |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
Takes a stream of matching statements and returns a boolean query result stream. |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
=end private |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
=cut |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
sub ask { |
740
|
8
|
|
|
8
|
1
|
14
|
my $self = shift; |
741
|
8
|
|
|
|
|
12
|
my $stream = shift; |
742
|
8
|
|
|
|
|
14
|
my $context = shift; |
743
|
8
|
|
|
|
|
32
|
my $value = $stream->next; |
744
|
8
|
100
|
|
|
|
88
|
my $bool = ($value) ? 1 : 0; |
745
|
8
|
|
|
|
|
103
|
return RDF::Trine::Iterator::Boolean->new( [ $bool ] ); |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
###################################################################### |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=item C<< pattern >> |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
Returns the RDF::Query::Algebra::GroupGraphPattern algebra pattern for this query. |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
=cut |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
sub pattern { |
757
|
430
|
|
|
430
|
1
|
705
|
my $self = shift; |
758
|
430
|
|
|
|
|
1109
|
my $parsed = $self->parsed; |
759
|
430
|
|
|
|
|
639
|
my @triples = @{ $parsed->{triples} }; |
|
430
|
|
|
|
|
1066
|
|
760
|
430
|
100
|
66
|
|
|
15921
|
if (scalar(@triples) == 1 and ($triples[0]->isa('RDF::Query::Algebra::GroupGraphPattern') |
|
|
|
66
|
|
|
|
|
761
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Filter') |
762
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Sort') |
763
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Limit') |
764
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Offset') |
765
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Distinct') |
766
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Project') |
767
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Construct') |
768
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Load') |
769
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Clear') |
770
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Create') |
771
|
|
|
|
|
|
|
or $triples[0]->isa('RDF::Query::Algebra::Update') |
772
|
|
|
|
|
|
|
)) { |
773
|
427
|
|
|
|
|
666
|
my $ggp = $triples[0]; |
774
|
427
|
|
|
|
|
1092
|
return $ggp; |
775
|
|
|
|
|
|
|
} else { |
776
|
3
|
|
|
|
|
17
|
return RDF::Query::Algebra::GroupGraphPattern->new( @triples ); |
777
|
|
|
|
|
|
|
} |
778
|
|
|
|
|
|
|
} |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
=item C<< is_update >> |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=cut |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
sub is_update { |
785
|
48
|
|
|
48
|
1
|
4118
|
my $self = shift; |
786
|
48
|
|
|
|
|
174
|
my $pat = $self->pattern; |
787
|
48
|
50
|
|
|
|
220
|
return 1 if ($pat->subpatterns_of_type('RDF::Query::Algebra::Clear')); |
788
|
48
|
50
|
|
|
|
164
|
return 1 if ($pat->subpatterns_of_type('RDF::Query::Algebra::Copy')); |
789
|
48
|
50
|
|
|
|
164
|
return 1 if ($pat->subpatterns_of_type('RDF::Query::Algebra::Create')); |
790
|
48
|
50
|
|
|
|
164
|
return 1 if ($pat->subpatterns_of_type('RDF::Query::Algebra::Move')); |
791
|
48
|
100
|
|
|
|
158
|
return 1 if ($pat->subpatterns_of_type('RDF::Query::Algebra::Update')); |
792
|
42
|
|
|
|
|
155
|
return 0; |
793
|
|
|
|
|
|
|
} |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
=item C<< as_sparql >> |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
Returns the query as a string in the SPARQL syntax. |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
=cut |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
sub as_sparql { |
802
|
33
|
|
|
33
|
1
|
574
|
my $self = shift; |
803
|
33
|
|
50
|
|
|
101
|
my $parsed = $self->parsed || {}; |
804
|
|
|
|
|
|
|
|
805
|
33
|
100
|
|
|
|
50
|
my $context = { namespaces => { %{ $parsed->{namespaces} || {} } } }; |
|
33
|
|
|
|
|
211
|
|
806
|
33
|
|
|
|
|
100
|
my $method = $parsed->{method}; |
807
|
|
|
|
|
|
|
|
808
|
33
|
100
|
|
|
|
137
|
if ($method =~ /^(DESCRIBE|ASK)$/i) { |
809
|
4
|
|
|
|
|
9
|
$context->{force_ggp_braces} = 1; |
810
|
|
|
|
|
|
|
} |
811
|
|
|
|
|
|
|
|
812
|
33
|
|
|
|
|
58
|
my @vars = map { $_->as_sparql( $context, '' ) } @{ $parsed->{ variables } }; |
|
34
|
|
|
|
|
162
|
|
|
33
|
|
|
|
|
78
|
|
813
|
33
|
|
|
|
|
338
|
my $vars = join(' ', @vars); |
814
|
33
|
|
|
|
|
101
|
my $ggp = $self->pattern; |
815
|
|
|
|
|
|
|
|
816
|
33
|
50
|
|
|
|
114
|
if ($method =~ /^(LOAD|CLEAR|CREATE|UPDATE)$/) { |
817
|
0
|
|
|
|
|
0
|
return $ggp->as_sparql; |
818
|
|
|
|
|
|
|
} else { |
819
|
|
|
|
|
|
|
{ |
820
|
33
|
|
|
|
|
43
|
my $pvars = join(' ', sort $ggp->referenced_variables); |
|
33
|
|
|
|
|
136
|
|
821
|
33
|
50
|
|
|
|
61
|
my $svars = join(' ', sort map { $_->isa('RDF::Query::Node::Resource') ? $_->as_string : $_->name } @{ $parsed->{ variables } }); |
|
34
|
|
|
|
|
232
|
|
|
33
|
|
|
|
|
78
|
|
822
|
33
|
100
|
|
|
|
225
|
if ($pvars eq $svars) { |
823
|
15
|
|
|
|
|
31
|
$vars = '*'; |
824
|
|
|
|
|
|
|
} |
825
|
|
|
|
|
|
|
} |
826
|
|
|
|
|
|
|
|
827
|
33
|
50
|
|
|
|
47
|
my @ns = map { "PREFIX " . ($_ eq '__DEFAULT__' ? '' : $_) . ": <$parsed->{namespaces}{$_}>" } (sort keys %{ $parsed->{namespaces} }); |
|
39
|
|
|
|
|
200
|
|
|
33
|
|
|
|
|
102
|
|
828
|
33
|
|
|
|
|
60
|
my @mod; |
829
|
33
|
50
|
|
|
|
134
|
if (my $ob = $parsed->{options}{orderby}) { |
830
|
|
|
|
|
|
|
push(@mod, 'ORDER BY ' . join(' ', map { |
831
|
0
|
|
|
|
|
0
|
my ($dir,$v) = @$_; |
|
0
|
|
|
|
|
0
|
|
832
|
0
|
0
|
|
|
|
0
|
($dir eq 'ASC') |
833
|
|
|
|
|
|
|
? $v->as_sparql( $context, '' ) |
834
|
|
|
|
|
|
|
: "${dir}" . $v->as_sparql( $context, '' ); |
835
|
|
|
|
|
|
|
} @$ob)); |
836
|
|
|
|
|
|
|
} |
837
|
33
|
50
|
|
|
|
91
|
if (my $l = $parsed->{options}{limit}) { |
838
|
0
|
|
|
|
|
0
|
push(@mod, "LIMIT $l"); |
839
|
|
|
|
|
|
|
} |
840
|
33
|
50
|
|
|
|
81
|
if (my $o = $parsed->{options}{offset}) { |
841
|
0
|
|
|
|
|
0
|
push(@mod, "OFFSET $o"); |
842
|
|
|
|
|
|
|
} |
843
|
33
|
|
|
|
|
64
|
my $mod = join("\n", @mod); |
844
|
|
|
|
|
|
|
|
845
|
33
|
|
|
|
|
59
|
my $methoddata = ''; |
846
|
33
|
100
|
|
|
|
92
|
if ($method eq 'SELECT') { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
847
|
27
|
|
|
|
|
42
|
$methoddata = $method; |
848
|
|
|
|
|
|
|
} elsif ($method eq 'ASK') { |
849
|
2
|
|
|
|
|
4
|
$methoddata = $method; |
850
|
|
|
|
|
|
|
} elsif ($method eq 'DESCRIBE') { |
851
|
2
|
|
|
|
|
10
|
$methoddata = sprintf("%s %s\nWHERE", $method, $vars); |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
|
854
|
33
|
100
|
|
|
|
108
|
my $ns = scalar(@ns) ? join("\n", @ns, '') : ''; |
855
|
33
|
|
|
|
|
41
|
my $sparql; |
856
|
33
|
50
|
66
|
|
|
135
|
if ($methoddata or $ns) { |
857
|
33
|
|
|
|
|
147
|
$sparql = sprintf( |
858
|
|
|
|
|
|
|
"$ns%s %s\n%s", |
859
|
|
|
|
|
|
|
$methoddata, |
860
|
|
|
|
|
|
|
$ggp->as_sparql( $context, '' ), |
861
|
|
|
|
|
|
|
$mod, |
862
|
|
|
|
|
|
|
); |
863
|
|
|
|
|
|
|
} else { |
864
|
0
|
|
|
|
|
0
|
$sparql = sprintf( |
865
|
|
|
|
|
|
|
"%s\n%s", |
866
|
|
|
|
|
|
|
$ggp->as_sparql( $context, '' ), |
867
|
|
|
|
|
|
|
$mod, |
868
|
|
|
|
|
|
|
); |
869
|
|
|
|
|
|
|
} |
870
|
|
|
|
|
|
|
|
871
|
33
|
|
|
|
|
92
|
chomp($sparql); |
872
|
33
|
|
|
|
|
227
|
return $sparql; |
873
|
|
|
|
|
|
|
} |
874
|
|
|
|
|
|
|
} |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
=item C<< as_hash >> |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
Returns the query as a nested set of plain data structures (no objects). |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
=cut |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
sub as_hash { |
883
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
884
|
0
|
|
|
|
|
0
|
my $pattern = $self->pattern; |
885
|
0
|
|
|
|
|
0
|
return $pattern->as_hash; |
886
|
|
|
|
|
|
|
} |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
=item C<< sse >> |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
Returns the query as a string in the SSE syntax. |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=cut |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
sub sse { |
895
|
13
|
|
|
13
|
1
|
54
|
my $self = shift; |
896
|
13
|
|
|
|
|
40
|
my $parsed = $self->parsed; |
897
|
|
|
|
|
|
|
|
898
|
13
|
|
|
|
|
49
|
my $ggp = $self->pattern; |
899
|
13
|
|
|
|
|
30
|
my $ns = $parsed->{namespaces}; |
900
|
13
|
|
|
|
|
17
|
my $nscount = scalar(@{ [ keys %$ns ] }); |
|
13
|
|
|
|
|
42
|
|
901
|
13
|
|
|
|
|
30
|
my $base_uri = $parsed->{base}; |
902
|
|
|
|
|
|
|
|
903
|
13
|
|
|
|
|
25
|
my $indent = ' '; |
904
|
13
|
|
|
|
|
50
|
my $context = { namespaces => $ns, indent => $indent }; |
905
|
13
|
|
|
|
|
19
|
my $indentcount = 0; |
906
|
13
|
100
|
|
|
|
36
|
$indentcount++ if ($base_uri); |
907
|
13
|
100
|
|
|
|
40
|
$indentcount++ if ($nscount); |
908
|
13
|
|
|
|
|
30
|
my $prefix = $indent x $indentcount; |
909
|
|
|
|
|
|
|
|
910
|
13
|
|
|
|
|
93
|
my $sse = $ggp->sse( $context, $prefix ); |
911
|
|
|
|
|
|
|
|
912
|
13
|
100
|
|
|
|
54
|
if ($nscount) { |
913
|
8
|
|
|
|
|
33
|
$sse = sprintf("(prefix (%s)\n${prefix}%s)", join("\n${indent}" . ' 'x9, map { "(${_}: <$ns->{$_}>)" } (sort keys %$ns)), $sse); |
|
9
|
|
|
|
|
53
|
|
914
|
|
|
|
|
|
|
} |
915
|
|
|
|
|
|
|
|
916
|
13
|
100
|
|
|
|
37
|
if ($base_uri) { |
917
|
1
|
|
|
|
|
13
|
$sse = sprintf("(base <%s>\n${indent}%s)", $base_uri->uri_value, $sse); |
918
|
|
|
|
|
|
|
} |
919
|
|
|
|
|
|
|
|
920
|
13
|
|
|
|
|
34
|
chomp($sse); |
921
|
13
|
|
|
|
|
67
|
return $sse; |
922
|
|
|
|
|
|
|
} |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
=item C<< dateparser >> |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
Returns the DateTime::Format::W3CDTF object associated with this query object. |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
=cut |
929
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
sub dateparser { |
931
|
2
|
|
|
2
|
1
|
3
|
my $self = shift; |
932
|
2
|
|
33
|
|
|
24
|
my $parser = ($self->{dateparser} ||= DateTime::Format::W3CDTF->new); |
933
|
2
|
|
|
|
|
19
|
return $parser; |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
=begin private |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
=item C<< supports ( $model, $feature ) >> |
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
Returns a boolean value representing the support of $feature for the given model. |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
=end private |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
=cut |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
sub supports { |
947
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
948
|
0
|
|
|
|
|
0
|
my $obj = shift; |
949
|
0
|
|
|
|
|
0
|
my $model = $self->get_model( $obj ); |
950
|
0
|
|
|
|
|
0
|
return $model->supports( @_ ); |
951
|
|
|
|
|
|
|
} |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
=item C<< specifies_update_dataset >> |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
Returns true if the query specifies a custom update dataset via the WITH or |
956
|
|
|
|
|
|
|
USING keywords, false otherwise. |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
=cut |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
sub specifies_update_dataset { |
961
|
3
|
|
|
3
|
1
|
21
|
my $self = shift; |
962
|
35
|
|
|
35
|
|
248
|
no warnings 'uninitialized'; |
|
35
|
|
|
|
|
82
|
|
|
35
|
|
|
|
|
80744
|
|
963
|
3
|
100
|
|
|
|
25
|
return $self->{parsed}{custom_update_dataset} ? 1 : 0; |
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
=begin private |
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
=item C<< get_model ( $model ) >> |
969
|
|
|
|
|
|
|
|
970
|
|
|
|
|
|
|
Returns a model object for use during execution. |
971
|
|
|
|
|
|
|
If C<< $model >> is a usable model, it is simply returned. |
972
|
|
|
|
|
|
|
Otherwise, a temporary model is constructed and returned. |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
=end private |
975
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
=cut |
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
sub get_model { |
979
|
158
|
|
|
158
|
1
|
270
|
my $self = shift; |
980
|
158
|
|
|
|
|
299
|
my $store = shift; |
981
|
158
|
|
|
|
|
322
|
my %args = @_; |
982
|
|
|
|
|
|
|
|
983
|
158
|
50
|
|
|
|
578
|
my $parsed = ref($self) ? $self->{parsed} : undef; |
984
|
|
|
|
|
|
|
|
985
|
158
|
|
|
|
|
235
|
my $model; |
986
|
158
|
100
|
|
|
|
1188
|
if (not $store) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
987
|
2
|
|
|
|
|
56
|
$model = RDF::Trine::Model->temporary_model; |
988
|
|
|
|
|
|
|
} elsif (($store->isa('RDF::Trine::Model'))) { |
989
|
156
|
|
|
|
|
294
|
$model = $store; |
990
|
|
|
|
|
|
|
} elsif ($store->isa('RDF::Redland::Model')) { |
991
|
0
|
|
|
|
|
0
|
my $s = RDF::Trine::Store->new_with_object( $store ); |
992
|
0
|
|
|
|
|
0
|
$model = RDF::Trine::Model->new( $s ); |
993
|
0
|
0
|
|
|
|
0
|
unless (blessed($model)) { |
994
|
0
|
|
|
|
|
0
|
Carp::cluck "Failed to construct an RDF::Trine model from $store"; |
995
|
0
|
|
|
|
|
0
|
return; |
996
|
|
|
|
|
|
|
} |
997
|
|
|
|
|
|
|
} elsif ($store->isa('RDF::Core::Model')) { |
998
|
0
|
|
|
|
|
0
|
Carp::croak "RDF::Core is no longer supported"; |
999
|
|
|
|
|
|
|
} else { |
1000
|
0
|
|
|
|
|
0
|
Carp::confess "unknown store type: $store"; |
1001
|
|
|
|
|
|
|
} |
1002
|
|
|
|
|
|
|
|
1003
|
158
|
|
|
|
|
959
|
return $model; |
1004
|
|
|
|
|
|
|
} |
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
=begin private |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
=item C<< load_data >> |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
Loads any external data required by this query (FROM and FROM NAMED clauses). |
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
=end private |
1013
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
=cut |
1015
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
sub load_data { |
1017
|
100
|
|
|
100
|
1
|
188
|
my $self = shift; |
1018
|
100
|
|
|
|
|
197
|
my $parsed = $self->{parsed}; |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
## LOAD ANY EXTERNAL RDF FILES |
1021
|
100
|
|
|
|
|
215
|
my $sources = $parsed->{'sources'}; |
1022
|
100
|
100
|
66
|
|
|
1001
|
if (ref($sources) and reftype($sources) eq 'ARRAY' and scalar(@$sources)) { |
|
|
|
100
|
|
|
|
|
1023
|
13
|
|
|
|
|
144
|
my $model = RDF::Trine::Model->temporary_model; |
1024
|
13
|
|
|
|
|
1065
|
$self->model( $model ); |
1025
|
13
|
|
|
|
|
47
|
foreach my $source (@$sources) { |
1026
|
23
|
|
66
|
|
|
710418
|
my $named_source = (2 == @{$source} and $source->[1] eq 'NAMED'); |
1027
|
23
|
|
|
|
|
119
|
my $uri = $source->[0]->uri_value; |
1028
|
23
|
|
|
|
|
270
|
$self->parse_url( $uri, $named_source ); |
1029
|
|
|
|
|
|
|
} |
1030
|
13
|
|
|
|
|
595816
|
$self->run_hook( 'http://kasei.us/code/rdf-query/hooks/post-create-model', $model ); |
1031
|
|
|
|
|
|
|
} |
1032
|
|
|
|
|
|
|
} |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
=begin private |
1036
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
=item C<< var_or_expr_value ( \%bound, $value, $context ) >> |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
Returns an (non-variable) RDF::Query::Node value based on C<< $value >>. |
1040
|
|
|
|
|
|
|
If C<< $value >> is a node object, it is simply returned. If it is an |
1041
|
|
|
|
|
|
|
RDF::Query::Node::Variable object, the corresponding value in C<< \%bound >> |
1042
|
|
|
|
|
|
|
is returned. If it is an RDF::Query::Expression object, the expression |
1043
|
|
|
|
|
|
|
is evaluated using C<< \%bound >>, and the resulting value is returned. |
1044
|
|
|
|
|
|
|
|
1045
|
|
|
|
|
|
|
=end private |
1046
|
|
|
|
|
|
|
|
1047
|
|
|
|
|
|
|
=cut |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
sub var_or_expr_value { |
1050
|
334
|
|
|
334
|
1
|
456
|
my $self = shift; |
1051
|
334
|
|
|
|
|
403
|
my $bound = shift; |
1052
|
334
|
|
|
|
|
417
|
my $v = shift; |
1053
|
334
|
|
|
|
|
415
|
my $ctx = shift; |
1054
|
334
|
50
|
|
|
|
1151
|
Carp::confess 'not an object value in var_or_expr_value: ' . Dumper($v) unless (blessed($v)); |
1055
|
334
|
100
|
|
|
|
2222
|
if ($v->isa('RDF::Query::Expression')) { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1056
|
44
|
|
|
|
|
166
|
return $v->evaluate( $self, $bound, $ctx ); |
1057
|
|
|
|
|
|
|
} elsif ($v->isa('RDF::Trine::Node::Variable')) { |
1058
|
263
|
|
|
|
|
793
|
return $bound->{ $v->name }; |
1059
|
|
|
|
|
|
|
} elsif ($v->isa('RDF::Query::Node')) { |
1060
|
27
|
|
|
|
|
103
|
return $v; |
1061
|
|
|
|
|
|
|
} else { |
1062
|
0
|
|
|
|
|
0
|
Carp::cluck "not an expression or node value in var_or_expr_value: " . Dumper($v, $bound); |
1063
|
0
|
|
|
|
|
0
|
throw RDF::Query::Error -text => 'Not an expression or node value'; |
1064
|
|
|
|
|
|
|
} |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
|
1068
|
|
|
|
|
|
|
=item C<add_function ( $uri, $function )> |
1069
|
|
|
|
|
|
|
|
1070
|
|
|
|
|
|
|
Associates the custom function C<$function> (a CODE reference) with the |
1071
|
|
|
|
|
|
|
specified URI, allowing the function to be called by query FILTERs. |
1072
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
=cut |
1074
|
|
|
|
|
|
|
|
1075
|
|
|
|
|
|
|
sub add_function { |
1076
|
2
|
|
|
2
|
1
|
47
|
my $self = shift; |
1077
|
2
|
|
|
|
|
4
|
my $uri = shift; |
1078
|
2
|
|
|
|
|
4
|
my $code = shift; |
1079
|
2
|
100
|
|
|
|
9
|
if (ref($self)) { |
1080
|
1
|
|
|
|
|
6
|
$self->{'functions'}{$uri} = $code; |
1081
|
|
|
|
|
|
|
} else { |
1082
|
1
|
|
|
|
|
3
|
our %functions; |
1083
|
1
|
|
|
|
|
5
|
$RDF::Query::functions{ $uri } = $code; |
1084
|
|
|
|
|
|
|
} |
1085
|
|
|
|
|
|
|
} |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
=item C<< supported_extensions >> |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
Returns a list of URLs representing extensions to SPARQL that are supported |
1090
|
|
|
|
|
|
|
by the query engine. |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
=cut |
1093
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
sub supported_extensions { |
1095
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1096
|
0
|
|
|
|
|
0
|
return qw( |
1097
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/service |
1098
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/service/bloom_filters |
1099
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/unsaid |
1100
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/federate_bindings |
1101
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/select_expression |
1102
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/aggregate |
1103
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/aggregate/count |
1104
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/aggregate/count-distinct |
1105
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/aggregate/min |
1106
|
|
|
|
|
|
|
http://kasei.us/2008/04/sparql-extension/aggregate/max |
1107
|
|
|
|
|
|
|
); |
1108
|
|
|
|
|
|
|
} |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
=item C<< supported_functions >> |
1111
|
|
|
|
|
|
|
|
1112
|
|
|
|
|
|
|
Returns a list URLs that may be used as functions in FILTER clauses |
1113
|
|
|
|
|
|
|
(and the SELECT clause if the SPARQL 1.1 parser is used). |
1114
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
=cut |
1116
|
|
|
|
|
|
|
|
1117
|
|
|
|
|
|
|
sub supported_functions { |
1118
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1119
|
0
|
|
|
|
|
0
|
my @funcs; |
1120
|
|
|
|
|
|
|
|
1121
|
0
|
0
|
|
|
|
0
|
if (blessed($self)) { |
1122
|
0
|
|
|
|
|
0
|
push(@funcs, keys %{ $self->{'functions'} }); |
|
0
|
|
|
|
|
0
|
|
1123
|
|
|
|
|
|
|
} |
1124
|
|
|
|
|
|
|
|
1125
|
0
|
|
|
|
|
0
|
push(@funcs, keys %RDF::Query::functions); |
1126
|
0
|
|
|
|
|
0
|
return grep { not(/^sparql:/) } @funcs; |
|
0
|
|
|
|
|
0
|
|
1127
|
|
|
|
|
|
|
} |
1128
|
|
|
|
|
|
|
|
1129
|
|
|
|
|
|
|
=begin private |
1130
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
=item C<get_function ( $uri, %args )> |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
If C<$uri> is associated with a query function, returns a CODE reference |
1134
|
|
|
|
|
|
|
to the function. Otherwise returns C<undef>. |
1135
|
|
|
|
|
|
|
|
1136
|
|
|
|
|
|
|
=end private |
1137
|
|
|
|
|
|
|
|
1138
|
|
|
|
|
|
|
=cut |
1139
|
|
|
|
|
|
|
|
1140
|
|
|
|
|
|
|
sub get_function { |
1141
|
354
|
|
|
354
|
1
|
489
|
my $self = shift; |
1142
|
354
|
|
|
|
|
488
|
my $uri = shift; |
1143
|
354
|
|
|
|
|
616
|
my %args = @_; |
1144
|
354
|
|
|
|
|
1185
|
my $l = Log::Log4perl->get_logger("rdf.query"); |
1145
|
354
|
50
|
33
|
|
|
9667
|
if (blessed($uri) and $uri->isa('RDF::Query::Node::Resource')) { |
1146
|
354
|
|
|
|
|
1065
|
$uri = $uri->uri_value; |
1147
|
|
|
|
|
|
|
} |
1148
|
354
|
|
|
|
|
2439
|
$l->debug("trying to get function from $uri"); |
1149
|
|
|
|
|
|
|
|
1150
|
354
|
50
|
33
|
|
|
3294
|
if (blessed($uri) and $uri->isa('RDF::Query::Node::Resource')) { |
1151
|
0
|
|
|
|
|
0
|
$uri = $uri->uri_value; |
1152
|
|
|
|
|
|
|
} |
1153
|
|
|
|
|
|
|
|
1154
|
354
|
|
|
|
|
481
|
my $func; |
1155
|
354
|
100
|
|
|
|
727
|
if (ref($self)) { |
1156
|
255
|
|
66
|
|
|
1184
|
$func = $self->{'functions'}{$uri} || $RDF::Query::functions{ $uri }; |
1157
|
|
|
|
|
|
|
} else { |
1158
|
99
|
|
|
|
|
325
|
$func = $RDF::Query::functions{ $uri }; |
1159
|
|
|
|
|
|
|
} |
1160
|
|
|
|
|
|
|
|
1161
|
354
|
50
|
|
|
|
812
|
if ($func) { |
1162
|
354
|
|
|
|
|
1098
|
return $func; |
1163
|
|
|
|
|
|
|
} |
1164
|
0
|
|
|
|
|
0
|
return; |
1165
|
|
|
|
|
|
|
} |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
=begin private |
1169
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
=item C<< call_function ( $model, $bound, $uri, @args ) >> |
1171
|
|
|
|
|
|
|
|
1172
|
|
|
|
|
|
|
If C<$uri> is associated with a query function, calls the function with the supplied arguments. |
1173
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
=end private |
1175
|
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
=cut |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
sub call_function { |
1179
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1180
|
0
|
|
|
|
|
0
|
my $model = shift; |
1181
|
0
|
|
|
|
|
0
|
my $bound = shift; |
1182
|
0
|
|
|
|
|
0
|
my $uri = shift; |
1183
|
0
|
|
|
|
|
0
|
my $l = Log::Log4perl->get_logger("rdf.query"); |
1184
|
0
|
|
|
|
|
0
|
$l->debug("trying to get function from $uri"); |
1185
|
|
|
|
|
|
|
|
1186
|
0
|
|
|
|
|
0
|
my $filter = RDF::Query::Expression::Function->new( $uri, @_ ); |
1187
|
0
|
|
|
|
|
0
|
return $filter->evaluate( $self, $bound ); |
1188
|
|
|
|
|
|
|
} |
1189
|
|
|
|
|
|
|
|
1190
|
|
|
|
|
|
|
=item C<< add_computed_statement_generator ( $predicate => \&generator ) >> |
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
Adds a statement generator for the given C<< $predicate >> to the query object. |
1193
|
|
|
|
|
|
|
This statement generator will be called as |
1194
|
|
|
|
|
|
|
C<< $generator->( $query, $model, \%bound, $s, $p, $o, $c ) >> |
1195
|
|
|
|
|
|
|
and is expected to return an RDF::Trine::Iterator::Graph object containing |
1196
|
|
|
|
|
|
|
statements with C<< $predicate >>. |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
=cut |
1199
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
sub add_computed_statement_generator { |
1201
|
1
|
|
|
1
|
1
|
8
|
my $self = shift; |
1202
|
1
|
50
|
|
|
|
5
|
if (scalar(@_) == 1) { |
1203
|
0
|
|
|
|
|
0
|
throw RDF::Query::Error::MethodInvocationError -text => 'RDF::Query::add_computed_statement_generator must now take two arguments: ( $predicate, \&generator ).'; |
1204
|
|
|
|
|
|
|
} |
1205
|
1
|
|
|
|
|
3
|
my $pred = shift; |
1206
|
1
|
|
|
|
|
2
|
my $gen = shift; |
1207
|
1
|
50
|
|
|
|
5
|
if (blessed($pred)) { |
1208
|
0
|
0
|
|
|
|
0
|
if ($pred->can('uri_value')) { |
1209
|
0
|
|
|
|
|
0
|
$pred = $pred->uri_value; |
1210
|
|
|
|
|
|
|
} else { |
1211
|
0
|
|
|
|
|
0
|
$pred = "$pred"; |
1212
|
|
|
|
|
|
|
} |
1213
|
|
|
|
|
|
|
} |
1214
|
1
|
|
|
|
|
3
|
push( @{ $self->{'computed_statement_generators'}{ $pred } }, $gen ); |
|
1
|
|
|
|
|
5
|
|
1215
|
|
|
|
|
|
|
} |
1216
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
=item C<< get_computed_statement_generators ( [ $predicate ] ) >> |
1218
|
|
|
|
|
|
|
|
1219
|
|
|
|
|
|
|
Returns an ARRAY reference of computed statement generator closures. |
1220
|
|
|
|
|
|
|
|
1221
|
|
|
|
|
|
|
=cut |
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
sub get_computed_statement_generators { |
1224
|
409
|
|
|
409
|
1
|
3515
|
my $self = shift; |
1225
|
409
|
50
|
|
|
|
949
|
if (@_) { |
1226
|
409
|
|
|
|
|
578
|
my $pred = shift; |
1227
|
409
|
50
|
|
|
|
1187
|
if (blessed($pred)) { |
1228
|
0
|
0
|
|
|
|
0
|
if ($pred->can('uri_value')) { |
1229
|
0
|
|
|
|
|
0
|
$pred = $pred->uri_value; |
1230
|
|
|
|
|
|
|
} else { |
1231
|
0
|
|
|
|
|
0
|
$pred = "$pred"; |
1232
|
|
|
|
|
|
|
} |
1233
|
|
|
|
|
|
|
} |
1234
|
409
|
|
100
|
|
|
2917
|
return $self->{'computed_statement_generators'}{ $pred } || []; |
1235
|
|
|
|
|
|
|
} else { |
1236
|
0
|
|
0
|
|
|
0
|
return $self->{'computed_statement_generators'} || {}; |
1237
|
|
|
|
|
|
|
} |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
=item C<< add_hook_once ( $hook_uri, $function, $token ) >> |
1241
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
Calls C<< add_hook >> adding the supplied C<< $function >> only once based on |
1243
|
|
|
|
|
|
|
the C<< $token >> identifier. This may be useful if the only code that is able |
1244
|
|
|
|
|
|
|
to add a hook is called many times (in an extension function, for example). |
1245
|
|
|
|
|
|
|
|
1246
|
|
|
|
|
|
|
=cut |
1247
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
sub add_hook_once { |
1249
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1250
|
0
|
|
|
|
|
0
|
my $uri = shift; |
1251
|
0
|
|
|
|
|
0
|
my $code = shift; |
1252
|
0
|
|
|
|
|
0
|
my $token = shift; |
1253
|
0
|
0
|
|
|
|
0
|
unless ($self->{'hooks_once'}{ $token }++) { |
1254
|
0
|
|
|
|
|
0
|
$self->add_hook( $uri, $code ); |
1255
|
|
|
|
|
|
|
} |
1256
|
|
|
|
|
|
|
} |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
=item C<< add_hook ( $hook_uri, $function ) >> |
1259
|
|
|
|
|
|
|
|
1260
|
|
|
|
|
|
|
Associates the custom function C<$function> (a CODE reference) with the |
1261
|
|
|
|
|
|
|
RDF::Query code hook specified by C<$uri>. Each function that has been |
1262
|
|
|
|
|
|
|
associated with a particular hook will be called (in the order they were |
1263
|
|
|
|
|
|
|
registered as hooks) when the hook event occurs. See L</"Defined Hooks"> |
1264
|
|
|
|
|
|
|
for more information. |
1265
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
=cut |
1267
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
sub add_hook { |
1269
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1270
|
0
|
|
|
|
|
0
|
my $uri = shift; |
1271
|
0
|
|
|
|
|
0
|
my $code = shift; |
1272
|
0
|
0
|
|
|
|
0
|
if (ref($self)) { |
1273
|
0
|
|
|
|
|
0
|
push(@{ $self->{'hooks'}{$uri} }, $code); |
|
0
|
|
|
|
|
0
|
|
1274
|
|
|
|
|
|
|
} else { |
1275
|
0
|
|
|
|
|
0
|
our %hooks; |
1276
|
0
|
|
|
|
|
0
|
push(@{ $RDF::Query::hooks{ $uri } }, $code); |
|
0
|
|
|
|
|
0
|
|
1277
|
|
|
|
|
|
|
} |
1278
|
|
|
|
|
|
|
} |
1279
|
|
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
=begin private |
1281
|
|
|
|
|
|
|
|
1282
|
|
|
|
|
|
|
=item C<get_hooks ( $uri )> |
1283
|
|
|
|
|
|
|
|
1284
|
|
|
|
|
|
|
If C<$uri> is associated with any query callback functions ("hooks"), |
1285
|
|
|
|
|
|
|
returns an ARRAY reference to the functions. If no hooks are associated |
1286
|
|
|
|
|
|
|
with C<$uri>, returns a reference to an empty array. |
1287
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
=end private |
1289
|
|
|
|
|
|
|
|
1290
|
|
|
|
|
|
|
=cut |
1291
|
|
|
|
|
|
|
|
1292
|
|
|
|
|
|
|
sub get_hooks { |
1293
|
202
|
|
|
202
|
1
|
326
|
my $self = shift; |
1294
|
202
|
|
|
|
|
328
|
my $uri = shift; |
1295
|
|
|
|
|
|
|
my $func = $self->{'hooks'}{ $uri } |
1296
|
202
|
|
50
|
|
|
1687
|
|| $RDF::Query::hooks{ $uri } |
1297
|
|
|
|
|
|
|
|| []; |
1298
|
202
|
|
|
|
|
504
|
return $func; |
1299
|
|
|
|
|
|
|
} |
1300
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
=begin private |
1302
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
=item C<run_hook ( $uri, @args )> |
1304
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
Calls any query callback functions associated with C<$uri>. Each callback |
1306
|
|
|
|
|
|
|
is called with the query object as the first argument, followed by any |
1307
|
|
|
|
|
|
|
caller-supplied arguments from C<@args>. |
1308
|
|
|
|
|
|
|
|
1309
|
|
|
|
|
|
|
=end private |
1310
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
=cut |
1312
|
|
|
|
|
|
|
|
1313
|
|
|
|
|
|
|
sub run_hook { |
1314
|
202
|
|
|
202
|
1
|
364
|
my $self = shift; |
1315
|
202
|
|
|
|
|
352
|
my $uri = shift; |
1316
|
202
|
|
|
|
|
1175
|
my @args = @_; |
1317
|
202
|
|
|
|
|
770
|
my $hooks = $self->get_hooks( $uri ); |
1318
|
202
|
|
|
|
|
781
|
foreach my $hook (@$hooks) { |
1319
|
0
|
|
|
|
|
0
|
$hook->( $self, @args ); |
1320
|
|
|
|
|
|
|
} |
1321
|
|
|
|
|
|
|
} |
1322
|
|
|
|
|
|
|
|
1323
|
|
|
|
|
|
|
=begin private |
1324
|
|
|
|
|
|
|
|
1325
|
|
|
|
|
|
|
=item C<< parse_url ( $url, $named ) >> |
1326
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
Retrieve a remote file by URL, and parse RDF into the RDF store. |
1328
|
|
|
|
|
|
|
If $named is TRUE, associate all parsed triples with a named graph. |
1329
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
=end private |
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
=cut |
1333
|
|
|
|
|
|
|
sub parse_url { |
1334
|
23
|
|
|
23
|
1
|
39
|
my $self = shift; |
1335
|
23
|
|
|
|
|
44
|
my $url = shift; |
1336
|
23
|
|
|
|
|
43
|
my $named = shift; |
1337
|
23
|
|
|
|
|
76
|
my $model = $self->model; |
1338
|
|
|
|
|
|
|
|
1339
|
23
|
100
|
|
|
|
79
|
if ($named) { |
1340
|
16
|
|
|
|
|
119
|
RDF::Trine::Parser->parse_url_into_model( $url, $model, context => iri($url) ); |
1341
|
|
|
|
|
|
|
} else { |
1342
|
7
|
|
|
|
|
117
|
RDF::Trine::Parser->parse_url_into_model( $url, $model ); |
1343
|
|
|
|
|
|
|
} |
1344
|
|
|
|
|
|
|
} |
1345
|
|
|
|
|
|
|
|
1346
|
|
|
|
|
|
|
=begin private |
1347
|
|
|
|
|
|
|
|
1348
|
|
|
|
|
|
|
=item C<variables ()> |
1349
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
Returns a list of the ordered variables the query is selecting. |
1351
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
=end private |
1353
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
=cut |
1355
|
|
|
|
|
|
|
|
1356
|
|
|
|
|
|
|
sub variables { |
1357
|
333
|
|
|
333
|
1
|
520
|
my $self = shift; |
1358
|
333
|
|
66
|
|
|
893
|
my $parsed = shift || $self->parsed; |
1359
|
480
|
|
|
|
|
2985
|
my @vars = map { $_->name } |
1360
|
|
|
|
|
|
|
grep { |
1361
|
482
|
100
|
|
|
|
2284
|
$_->isa('RDF::Query::Node::Variable') or $_->isa('RDF::Query::Expression::Alias') |
1362
|
333
|
|
|
|
|
527
|
} @{ $parsed->{'variables'} }; |
|
333
|
|
|
|
|
844
|
|
1363
|
333
|
|
|
|
|
2762
|
return @vars; |
1364
|
|
|
|
|
|
|
} |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
=item C<parsed ()> |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
Returns the parse tree. |
1369
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
=cut |
1371
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
sub parsed { |
1373
|
494
|
|
|
494
|
1
|
681
|
my $self = shift; |
1374
|
494
|
50
|
|
|
|
1251
|
if (@_) { |
1375
|
0
|
|
|
|
|
0
|
$self->{parsed} = shift; |
1376
|
|
|
|
|
|
|
} |
1377
|
494
|
|
|
|
|
1051
|
return $self->{parsed}; |
1378
|
|
|
|
|
|
|
} |
1379
|
|
|
|
|
|
|
|
1380
|
|
|
|
|
|
|
=item C<< model >> |
1381
|
|
|
|
|
|
|
|
1382
|
|
|
|
|
|
|
Returns the RDF::Trine::Model object for this query. |
1383
|
|
|
|
|
|
|
|
1384
|
|
|
|
|
|
|
=cut |
1385
|
|
|
|
|
|
|
|
1386
|
|
|
|
|
|
|
sub model { |
1387
|
365
|
|
|
365
|
1
|
637
|
my $self = shift; |
1388
|
365
|
100
|
|
|
|
929
|
if (@_) { |
1389
|
171
|
|
|
|
|
378
|
$self->{model} = shift; |
1390
|
|
|
|
|
|
|
} |
1391
|
365
|
|
|
|
|
598
|
my $model = $self->{model}; |
1392
|
365
|
50
|
|
|
|
907
|
unless (defined $model) { |
1393
|
0
|
|
|
|
|
0
|
Carp::confess "query->model shouldn't be calling get_model"; |
1394
|
0
|
|
|
|
|
0
|
$model = $self->get_model(); |
1395
|
|
|
|
|
|
|
} |
1396
|
|
|
|
|
|
|
|
1397
|
365
|
|
|
|
|
663
|
return $model; |
1398
|
|
|
|
|
|
|
} |
1399
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
|
1401
|
|
|
|
|
|
|
=item C<< useragent >> |
1402
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
Returns the LWP::UserAgent object used for retrieving web content. |
1404
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
=cut |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
sub useragent { |
1408
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1409
|
0
|
0
|
|
|
|
0
|
if (my $ua = $self->{useragent}) { |
1410
|
0
|
|
|
|
|
0
|
return $ua; |
1411
|
|
|
|
|
|
|
} else { |
1412
|
0
|
|
|
|
|
0
|
my $ua = LWP::UserAgent->new( agent => "RDF::Query/${VERSION}" ); |
1413
|
0
|
|
|
|
|
0
|
$ua->default_headers->push_header( 'Accept' => "application/sparql-results+xml;q=0.9,application/rdf+xml;q=0.5,text/turtle;q=0.7,text/xml" ); |
1414
|
0
|
|
|
|
|
0
|
$self->{useragent} = $ua; |
1415
|
0
|
|
|
|
|
0
|
return $ua; |
1416
|
|
|
|
|
|
|
} |
1417
|
|
|
|
|
|
|
} |
1418
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
|
1420
|
|
|
|
|
|
|
=item C<< log ( $key [, $value ] ) >> |
1421
|
|
|
|
|
|
|
|
1422
|
|
|
|
|
|
|
If no logger object is associated with this query object, does nothing. |
1423
|
|
|
|
|
|
|
Otherwise, return or set the corresponding value depending on whether a |
1424
|
|
|
|
|
|
|
C<< $value >> is specified. |
1425
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
=cut |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
sub log { |
1429
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1430
|
0
|
0
|
|
|
|
0
|
if (blessed(my $l = $self->{ logger })) { |
1431
|
0
|
|
|
|
|
0
|
$l->log( @_ ); |
1432
|
|
|
|
|
|
|
} |
1433
|
|
|
|
|
|
|
} |
1434
|
|
|
|
|
|
|
|
1435
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
=item C<< logger >> |
1437
|
|
|
|
|
|
|
|
1438
|
|
|
|
|
|
|
Returns the logger object associated with this query object (if present). |
1439
|
|
|
|
|
|
|
|
1440
|
|
|
|
|
|
|
=cut |
1441
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
sub logger { |
1443
|
158
|
|
|
158
|
1
|
278
|
my $self = shift; |
1444
|
158
|
|
|
|
|
2236
|
return $self->{ logger }; |
1445
|
|
|
|
|
|
|
} |
1446
|
|
|
|
|
|
|
|
1447
|
|
|
|
|
|
|
=item C<error ()> |
1448
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
Returns the last error the parser experienced. |
1450
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
=cut |
1452
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
sub error { |
1454
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1455
|
0
|
0
|
|
|
|
0
|
if (blessed($self)) { |
1456
|
0
|
|
|
|
|
0
|
return $self->{error}; |
1457
|
|
|
|
|
|
|
} else { |
1458
|
0
|
|
|
|
|
0
|
our $_ERROR; |
1459
|
0
|
|
|
|
|
0
|
return $_ERROR; |
1460
|
|
|
|
|
|
|
} |
1461
|
|
|
|
|
|
|
} |
1462
|
|
|
|
|
|
|
|
1463
|
|
|
|
|
|
|
sub _uniq { |
1464
|
1414
|
|
|
1414
|
|
5612
|
my %seen; |
1465
|
|
|
|
|
|
|
my @data; |
1466
|
1414
|
|
|
|
|
2626
|
foreach (@_) { |
1467
|
928
|
100
|
|
|
|
3039
|
push(@data, $_) unless ($seen{ $_ }++); |
1468
|
|
|
|
|
|
|
} |
1469
|
1414
|
|
|
|
|
26236
|
return @data; |
1470
|
|
|
|
|
|
|
} |
1471
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
=begin private |
1473
|
|
|
|
|
|
|
|
1474
|
|
|
|
|
|
|
=item C<set_error ( $error )> |
1475
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
Sets the object's error variable. |
1477
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
=end private |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
=cut |
1481
|
|
|
|
|
|
|
|
1482
|
|
|
|
|
|
|
sub set_error { |
1483
|
2
|
|
|
2
|
1
|
3
|
my $self = shift; |
1484
|
2
|
|
|
|
|
4
|
my $error = shift; |
1485
|
2
|
|
|
|
|
4
|
my $e = shift; |
1486
|
2
|
50
|
|
|
|
8
|
if (blessed($self)) { |
1487
|
0
|
|
|
|
|
0
|
$self->{error} = $error; |
1488
|
0
|
|
|
|
|
0
|
$self->{exception} = $e; |
1489
|
|
|
|
|
|
|
} |
1490
|
2
|
|
|
|
|
5
|
our $_ERROR = $error; |
1491
|
2
|
|
|
|
|
5
|
our $_EXCEPTION = $e; |
1492
|
|
|
|
|
|
|
} |
1493
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
=begin private |
1495
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
=item C<clear_error ()> |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
Clears the object's error variable. |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
=end private |
1501
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
=cut |
1503
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
sub clear_error { |
1505
|
207
|
|
|
207
|
1
|
464
|
my $self = shift; |
1506
|
207
|
50
|
|
|
|
1015
|
if (blessed($self)) { |
1507
|
0
|
|
|
|
|
0
|
$self->{error} = undef; |
1508
|
0
|
|
|
|
|
0
|
$self->{exception} = undef; |
1509
|
|
|
|
|
|
|
} |
1510
|
207
|
|
|
|
|
396
|
our($_ERROR, $_EXCEPTION); |
1511
|
207
|
|
|
|
|
450
|
undef $_ERROR; |
1512
|
207
|
|
|
|
|
496
|
undef $_EXCEPTION; |
1513
|
|
|
|
|
|
|
} |
1514
|
|
|
|
|
|
|
|
1515
|
|
|
|
|
|
|
|
1516
|
|
|
|
|
|
|
# =begin private |
1517
|
|
|
|
|
|
|
# |
1518
|
|
|
|
|
|
|
# =item C<_debug_closure ( $code )> |
1519
|
|
|
|
|
|
|
# |
1520
|
|
|
|
|
|
|
# Debugging function to print out a deparsed (textual) version of a closure. |
1521
|
|
|
|
|
|
|
# |
1522
|
|
|
|
|
|
|
# =end private |
1523
|
|
|
|
|
|
|
# |
1524
|
|
|
|
|
|
|
# =cut |
1525
|
|
|
|
|
|
|
# |
1526
|
|
|
|
|
|
|
# sub _debug_closure { |
1527
|
|
|
|
|
|
|
# my $closure = shift; |
1528
|
|
|
|
|
|
|
# my $l = Log::Log4perl->get_logger("rdf.query"); |
1529
|
|
|
|
|
|
|
# if ($l->is_trace) { |
1530
|
|
|
|
|
|
|
# require B::Deparse; |
1531
|
|
|
|
|
|
|
# my $deparse = B::Deparse->new("-p", "-sC"); |
1532
|
|
|
|
|
|
|
# my $body = $deparse->coderef2text($closure); |
1533
|
|
|
|
|
|
|
# $l->trace("--- --- CLOSURE --- ---"); |
1534
|
|
|
|
|
|
|
# $l->logcluck($body); |
1535
|
|
|
|
|
|
|
# } |
1536
|
|
|
|
|
|
|
# } |
1537
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
|
1539
|
|
|
|
|
|
|
1; |
1540
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
__END__ |
1542
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
=back |
1544
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
=head1 DEFINED HOOKS |
1546
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
The following hook URIs are defined and may be used to extend the query engine |
1548
|
|
|
|
|
|
|
functionality using the C<< add_hook >> method: |
1549
|
|
|
|
|
|
|
|
1550
|
|
|
|
|
|
|
=over 4 |
1551
|
|
|
|
|
|
|
|
1552
|
|
|
|
|
|
|
=item http://kasei.us/code/rdf-query/hooks/post-create-model |
1553
|
|
|
|
|
|
|
|
1554
|
|
|
|
|
|
|
Called after loading all external files to a temporary model in queries that |
1555
|
|
|
|
|
|
|
use FROM and FROM NAMED. |
1556
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
Args: ( $query, $model ) |
1558
|
|
|
|
|
|
|
|
1559
|
|
|
|
|
|
|
C<$query> is the RDF::Query object. |
1560
|
|
|
|
|
|
|
C<$model> is the RDF::Trine::Model object. |
1561
|
|
|
|
|
|
|
|
1562
|
|
|
|
|
|
|
=item http://kasei.us/code/rdf-query/hooks/post-execute |
1563
|
|
|
|
|
|
|
|
1564
|
|
|
|
|
|
|
Called immediately before returning a result iterator from the execute method. |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
Args: ( $query, $model, $iterator ) |
1567
|
|
|
|
|
|
|
|
1568
|
|
|
|
|
|
|
C<$query> is the RDF::Query object. |
1569
|
|
|
|
|
|
|
C<$model> is the RDF::Trine::Model object. |
1570
|
|
|
|
|
|
|
C<$iterator> is a RDF::Trine::Iterator object. |
1571
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
=back |
1573
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
=head1 SEE ALSO |
1575
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
L<http://www.perlrdf.org/> |
1577
|
|
|
|
|
|
|
|
1578
|
|
|
|
|
|
|
=head1 AUTHOR |
1579
|
|
|
|
|
|
|
|
1580
|
|
|
|
|
|
|
Gregory Todd Williams <gwilliams@cpan.org> |
1581
|
|
|
|
|
|
|
|
1582
|
|
|
|
|
|
|
=head1 LICENSE |
1583
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
Copyright (c) 2005-2012 Gregory Todd Williams. This |
1585
|
|
|
|
|
|
|
program is free software; you can redistribute it and/or modify it under |
1586
|
|
|
|
|
|
|
the same terms as Perl itself. |
1587
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
=cut |