← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 19:05:14 2015
Reported on Fri Jul 31 19:08:11 2015

Filename/var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm
StatementsExecuted 194969 statements in 394ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
4111450ms48.6sFoswiki::Store::QueryAlgorithms::BruteForce::::_webQueryFoswiki::Store::QueryAlgorithms::BruteForce::_webQuery
876011229ms448msFoswiki::Store::QueryAlgorithms::BruteForce::::getFieldFoswiki::Store::QueryAlgorithms::BruteForce::getField
41117.16ms48.7sFoswiki::Store::QueryAlgorithms::BruteForce::::queryFoswiki::Store::QueryAlgorithms::BruteForce::query
1111.45ms1.53msFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@37Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@37
111238µs412µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@31Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@31
11114µs28µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@26Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@26
11111µs43µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@40Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@40
1119µs14µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@27Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@27
1115µs5µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@32Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@32
1114µs4µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@33Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@33
1113µs3µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@36Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@36
1113µs3µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@34Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@34
1113µs3µsFoswiki::Store::QueryAlgorithms::BruteForce::::BEGIN@35Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@35
0000s0sFoswiki::Store::QueryAlgorithms::BruteForce::::getRefTopicFoswiki::Store::QueryAlgorithms::BruteForce::getRefTopic
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3=begin TML
4
5---+ package Foswiki::Store::QueryAlgorithms::BruteForce
6
7Default brute-force query algorithm
8
9Has some basic optimisation: it hoists regular expressions out of the
10query to use with grep, so we can narrow down the set of topics that we
11have to evaluate the query on.
12
13Not sure exactly where the breakpoint is between the
14costs of hoisting and the advantages of hoisting. Benchmarks suggest
15that it's around 6 topics, though this may vary depending on disk
16speed and memory size. It also depends on the complexity of the query.
17
18TODO: There is an additional opprotunity for optimisation; if we assume
19the grep is solid, we can cut those parts of the query out for the full
20evaluation path. Not done yet, because CDot strongly suspects it won't make
21much difference.
22
23=cut
24
25package Foswiki::Store::QueryAlgorithms::BruteForce;
26228µs241µs
# spent 28µs (14+14) within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@26 which was called: # once (14µs+14µs) by Foswiki::Store::VC::Store::query at line 26
use strict;
# spent 28µs making 1 call to Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@26 # spent 14µs making 1 call to strict::import
27233µs220µs
# spent 14µs (9+5) within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@27 which was called: # once (9µs+5µs) by Foswiki::Store::VC::Store::query at line 27
use warnings;
# spent 14µs making 1 call to Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@27 # spent 5µs making 1 call to warnings::import
28
29#@ISA = ( 'Foswiki::Query::QueryAlgorithms' ); # interface
30
31297µs1412µs
# spent 412µs (238+174) within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@31 which was called: # once (238µs+174µs) by Foswiki::Store::VC::Store::query at line 31
use Foswiki::Search::Node ();
32220µs15µs
# spent 5µs within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@32 which was called: # once (5µs+0s) by Foswiki::Store::VC::Store::query at line 32
use Foswiki::Meta ();
33218µs14µs
# spent 4µs within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@33 which was called: # once (4µs+0s) by Foswiki::Store::VC::Store::query at line 33
use Foswiki::Search::InfoCache ();
34218µs13µs
# spent 3µs within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@34 which was called: # once (3µs+0s) by Foswiki::Store::VC::Store::query at line 34
use Foswiki::Search::ResultSet ();
35218µs13µs
# spent 3µs within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@35 which was called: # once (3µs+0s) by Foswiki::Store::VC::Store::query at line 35
use Foswiki::MetaCache ();
36217µs13µs
# spent 3µs within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@36 which was called: # once (3µs+0s) by Foswiki::Store::VC::Store::query at line 36
use Foswiki::Query::Node ();
372107µs11.53ms
# spent 1.53ms (1.45+85µs) within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@37 which was called: # once (1.45ms+85µs) by Foswiki::Store::VC::Store::query at line 37
use Foswiki::Query::HoistREs ();
38
39# See Foswiki::Query::QueryAlgorithms.pm for details
4021.26ms276µs
# spent 43µs (11+32) within Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@40 which was called: # once (11µs+32µs) by Foswiki::Store::VC::Store::query at line 40
use constant MONITOR => 0;
# spent 43µs making 1 call to Foswiki::Store::QueryAlgorithms::BruteForce::BEGIN@40 # spent 32µs making 1 call to constant::import
41
42
# spent 48.7s (7.16ms+48.7) within Foswiki::Store::QueryAlgorithms::BruteForce::query which was called 41 times, avg 1.19s/call: # 41 times (7.16ms+48.7s) by Foswiki::Store::VC::Store::query at line 518 of /var/www/foswiki11/lib/Foswiki/Store/VC/Store.pm, avg 1.19s/call
sub query {
434153µs my ( $query, $inputTopicSet, $session, $options ) = @_;
44
45 # Fold constants
4641156µs41681µs my $context = Foswiki::Meta->new( $session, $session->{webName} );
# spent 681µs making 41 calls to Foswiki::Meta::new, avg 17µs/call
47 print STDERR "--- before: " . $query->toString() . "\n" if MONITOR;
4841177µs413.58ms $query->simplify( tom => $context, data => $context );
# spent 3.58ms making 41 calls to Foswiki::Query::Node::simplify, avg 87µs/call
49 print STDERR "--- simplified: " . $query->toString() . "\n" if MONITOR;
50
514172µs my $webNames = $options->{web} || '';
524142µs my $recurse = $options->{'recurse'} || '';
5341272µs41412µs my $isAdmin = $session->{users}->isAdmin( $session->{user} );
# spent 412µs making 41 calls to Foswiki::Users::isAdmin, avg 10µs/call
54
554155µs my $searchAllFlag = ( $webNames =~ /(^|[\,\s])(all|on)([\,\s]|$)/i );
5641205µs412.77ms my @webs = Foswiki::Search::InfoCache::_getListOfWebs( $webNames, $recurse,
# spent 2.77ms making 41 calls to Foswiki::Search::InfoCache::_getListOfWebs, avg 68µs/call
57 $searchAllFlag );
58
59419µs my @resultCacheList;
604138µs foreach my $web (@webs) {
61
62 # can't process what ain't thar
6341129µs412.44ms next unless $session->webExists($web);
# spent 2.44ms making 41 calls to Foswiki::webExists, avg 59µs/call
64
6541146µs41649µs my $webObject = Foswiki::Meta->new( $session, $web );
# spent 649µs making 41 calls to Foswiki::Meta::new, avg 16µs/call
6641244µs8211.8ms my $thisWebNoSearchAll =
# spent 11.5ms making 41 calls to Foswiki::Meta::getPreference, avg 281µs/call # spent 313µs making 41 calls to Foswiki::isTrue, avg 8µs/call
67 Foswiki::isTrue( $webObject->getPreference('NOSEARCHALL') );
68
69 # make sure we can report this web on an 'all' search
70 # DON'T filter out unless it's part of an 'all' search.
71 next
724112µs if ( $searchAllFlag
73 && !$isAdmin
74 && ( $thisWebNoSearchAll || $web =~ /^[\.\_]/ )
75 && $web ne $session->{webName} );
76
77 #TODO: combine these into one great ResultSet
7841123µs4148.6s my $infoCache =
# spent 48.6s making 41 calls to Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery, avg 1.19s/call
79 _webQuery( $query, $web, $inputTopicSet, $session, $options );
8041293µs push( @resultCacheList, $infoCache );
81 }
8241386µs82391µs my $resultset =
# spent 271µs making 41 calls to Foswiki::Search::ResultSet::new, avg 7µs/call # spent 120µs making 41 calls to Foswiki::isTrue, avg 3µs/call
83 new Foswiki::Search::ResultSet( \@resultCacheList, $options->{groupby},
84 $options->{order}, Foswiki::isTrue( $options->{reverse} ) );
85
86 # first filter, then sort the remaining
874147µs my $date = $options->{'date'} || '';
884112µs if ($date) {
89 $resultset->filterByDate($date);
90 }
91
92 #TODO: $options should become redundant
934177µs4154.0ms $resultset->sortResults($options);
# spent 54.0ms making 41 calls to Foswiki::Search::ResultSet::sortResults, avg 1.32ms/call
9441448µs return $resultset;
95}
96
97# Query over a single web
98
# spent 48.6s (450ms+48.1) within Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery which was called 41 times, avg 1.19s/call: # 41 times (450ms+48.1s) by Foswiki::Store::QueryAlgorithms::BruteForce::query at line 78, avg 1.19s/call
sub _webQuery {
994154µs my ( $query, $web, $inputTopicSet, $session, $options ) = @_;
100
10141163µs41924µs my $resultTopicSet =
# spent 924µs making 41 calls to Foswiki::Search::InfoCache::new, avg 23µs/call
102 new Foswiki::Search::InfoCache( $Foswiki::Plugins::SESSION, $web );
103
104 # see if this query can be fasttracked.
105 # TODO: is this simplification call appropriate here, or should it
106 # go in Search.pm
107 # TODO: what about simplify to constant in _this_ web?
1084112µs my $queryIsAConstantFastpath; # undefined if this is a 'real' query'
1094172µs412.37ms $query->simplify();
# spent 2.37ms making 41 calls to Foswiki::Query::Node::simplify, avg 58µs/call
1104178µs41353µs if ( $query->evaluatesToConstant() ) {
# spent 353µs making 41 calls to Foswiki::Query::Node::evaluatesToConstant, avg 9µs/call
111 print STDERR "-- constant?\n" if MONITOR;
112
113 # SMELL: use any old topic
114110µs3737µs my $cache = $Foswiki::Plugins::SESSION->search->metacache->get( $web,
# spent 731µs making 1 call to Foswiki::MetaCache::get # spent 4µs making 1 call to Foswiki::Search::metacache # spent 2µs making 1 call to Foswiki::search
115 'WebPreferences' );
1161900ns my $meta = $cache->{tom};
11714µs123µs $queryIsAConstantFastpath =
# spent 23µs making 1 call to Foswiki::Query::Node::evaluate
118 $query->evaluate( tom => $meta, data => $meta );
119 }
120
1214121µs if ( defined($queryIsAConstantFastpath) ) {
1221300ns if ( not $queryIsAConstantFastpath ) {
123 print STDERR "-- no results\n" if MONITOR;
124
125 #CONSTANT _and_ FALSE - return no results
126 return $resultTopicSet;
127 }
128 }
129 else {
130 print STDERR "-- not constant\n" if MONITOR;
131
132 # from here on, FALSE means its not a constant, TRUE
133 # means is is a constant and evals to TRUE
1344022µs $queryIsAConstantFastpath = 0;
135 }
136
137 # Try and hoist regular expressions out of the query that we
138 # can use to refine the topic set
139
14041194µs413.02ms my $hoistedREs = Foswiki::Query::HoistREs::collatedHoist($query);
# spent 3.02ms making 41 calls to Foswiki::Query::HoistREs::collatedHoist, avg 74µs/call
141
142 # Reduce the input topic set by matching simple topic names hoisted
143 # from the query.
144
1454140µs if ( ( !defined( $options->{topic} ) )
146 and ( $hoistedREs->{name} )
147 and ( scalar( @{ $hoistedREs->{name} } ) == 1 ) )
148 {
149
150 # only do this if the 'name' query is simple
151 # (ie, has only one element)
152 my @filter = @{ $hoistedREs->{name_source} };
153
154 #set the 'includetopic' matcher..
155 $options->{topic} = $filter[0];
156 }
157
158 # Reduce the input topic set by matching the hoisted REs against
159 # the topics in it.
160
1614118µs my $topicSet = $inputTopicSet;
1624129µs if ( !defined($topicSet) ) {
163 print STDERR "-- new topic Set from $web\n" if MONITOR;
164
165 # then we start with the whole web?
166 # TODO: i'm sure that is a flawed assumption
16741134µs41655µs my $webObject = Foswiki::Meta->new( $session, $web );
# spent 655µs making 41 calls to Foswiki::Meta::new, avg 16µs/call
16841116µs41333ms $topicSet =
# spent 333ms making 41 calls to Foswiki::Search::InfoCache::getTopicListIterator, avg 8.11ms/call
169 Foswiki::Search::InfoCache::getTopicListIterator( $webObject,
170 $options );
171 }
172
173 # TODO: how to ask iterator for list length?
174 # TODO: once the inputTopicSet isa ResultSet we might have an idea
175 # TODO: I presume $hoisetedRE's is undefined for constant queries..
176 # if (() and ( scalar(@$topics) > 6 )) {
177418.98ms if ( defined( $hoistedREs->{text} ) ) {
1784079µs my $searchOptions = {
179 type => 'regex',
180 casesensitive => 1,
181 files_without_match => 1,
182 };
1834051µs my @filter = @{ $hoistedREs->{text} };
18440327µs802.97ms my $searchQuery =
# spent 2.74ms making 40 calls to Foswiki::Query::Node::toString, avg 68µs/call # spent 234µs making 40 calls to Foswiki::Search::Node::new, avg 6µs/call
185 new Foswiki::Search::Node( $query->toString(), \@filter,
186 $searchOptions );
187
188 #use Data::Dumper;
189 #print STDERR "--- hoisted: ".Dumper($hoistedREs)."\n" if MONITOR;
190
19140106µs40480µs $topicSet->reset();
# spent 480µs making 40 calls to Foswiki::Iterator::FilterIterator::reset, avg 12µs/call
19240805µs4043.5s $topicSet =
# spent 43.5s making 40 calls to Foswiki::Store::VC::Store::searchInWebMetaData, avg 1.09s/call
193 $session->{store}
194 ->searchInWebMetaData( $searchQuery, $web, $topicSet, $session,
195 $searchOptions );
196 }
197 else {
198
199 # TODO: clearly _this_ can be re-written as a FilterIterator,
200 # and if we are able to use the sorting hints (ie DB Store)
201 # can propogate all the way to FORMAT
202
2031300ns print STDERR "WARNING: couldn't hoistREs on " . $query->toString()
204 if MONITOR;
205 }
206
20741177µs local $/;
20841475µs41813µs $topicSet->reset();
# spent 798µs making 40 calls to Foswiki::Iterator::reset, avg 20µs/call # spent 15µs making 1 call to Foswiki::Iterator::FilterIterator::reset
20941248µs413.17ms while ( $topicSet->hasNext() ) {
# spent 2.57ms making 40 calls to Foswiki::Search::ResultSet::hasNext, avg 64µs/call # spent 599µs making 1 call to Foswiki::Iterator::FilterIterator::hasNext
210884514.8ms884579.2ms my $webtopic = $topicSet->next();
# spent 78.8ms making 8760 calls to Foswiki::Search::ResultSet::next, avg 9µs/call # spent 424µs making 85 calls to Foswiki::Iterator::FilterIterator::next, avg 5µs/call
211884517.2ms8845237ms my ( $Iweb, $topic ) =
# spent 237ms making 8845 calls to Foswiki::Func::normalizeWebTopicName, avg 27µs/call
212 Foswiki::Func::normalizeWebTopicName( $web, $webtopic );
213 print STDERR "-- $Iweb, $topic\n" if MONITOR;
214
215884521.3ms8845294ms if ($queryIsAConstantFastpath) {
# spent 236ms making 8760 calls to Foswiki::Search::ResultSet::hasNext, avg 27µs/call # spent 58.1ms making 85 calls to Foswiki::Iterator::FilterIterator::hasNext, avg 683µs/call
216 print STDERR "-- add $Iweb, $topic\n" if MONITOR;
2178540µs if ( defined( $options->{date} ) ) {
218
219 # TODO: preload the meta cache if we're doing date
220 # based filtering - else the wrong filedate will be used
221 $Foswiki::Plugins::SESSION->search->metacache->get( $Iweb,
222 $topic );
223 }
224
225 # TODO: frustratingly, there is no way to evaluate a
226 # filterIterator without actually iterating over it..
22785131µs852.01ms $resultTopicSet->addTopics( $Iweb, $topic );
# spent 2.01ms making 85 calls to Foswiki::Search::InfoCache::addTopics, avg 24µs/call
228 }
229 else {
230876035.8ms26280927ms my $cache =
# spent 891ms making 8760 calls to Foswiki::MetaCache::get, avg 102µs/call # spent 19.1ms making 8760 calls to Foswiki::search, avg 2µs/call # spent 17.1ms making 8760 calls to Foswiki::Search::metacache, avg 2µs/call
231 $Foswiki::Plugins::SESSION->search->metacache->get( $Iweb,
232 $topic );
233
23487608.93ms my $meta = $cache->{tom};
23587601.20ms next unless ( defined($meta) ); #not a valid or loadable topic
236
237 # this 'lazy load' will become useful when @$topics becomes
238 # an infoCache
239876014.0ms876054.6ms $meta = $meta->load() unless ( $meta->latestIsLoaded() );
# spent 54.6ms making 8760 calls to Foswiki::Meta::latestIsLoaded, avg 6µs/call
240876010.9ms87609.10ms print STDERR "Processing $topic\n"
# spent 9.10ms making 8760 calls to Foswiki::Query::Node::MONITOR_EVAL, avg 1µs/call
241 if Foswiki::Query::Node::MONITOR_EVAL;
242876015.0ms87601.99s my $match = $query->evaluate( tom => $meta, data => $meta );
# spent 1.99s making 8760 calls to Foswiki::Query::Node::evaluate, avg 227µs/call
243876019.1ms8760701ms if ($match) {
# spent 701ms making 8760 calls to Foswiki::Search::InfoCache::addTopic, avg 80µs/call
244 $resultTopicSet->addTopic($meta);
245 }
246 }
247 }
248
249411.01ms return $resultTopicSet;
250}
251
252# The getField function is here to allow for Store specific optimisations
253# such as direct database lookups.
254
# spent 448ms (229+219) within Foswiki::Store::QueryAlgorithms::BruteForce::getField which was called 8760 times, avg 51µs/call: # 8760 times (229ms+219ms) by Foswiki::Query::Node::evaluate at line 171 of /var/www/foswiki11/lib/Foswiki/Query/Node.pm, avg 51µs/call
sub getField {
25587608.92ms my ( $this, $node, $data, $field ) = @_;
256
25787601.28ms my $result;
258876060.6ms876012.2ms if ( UNIVERSAL::isa( $data, 'Foswiki::Meta' ) ) {
# spent 12.2ms making 8760 calls to UNIVERSAL::isa, avg 1µs/call
259
260 # The object being indexed is a Foswiki::Meta object, so
261 # we have to use a different approach to treating it
262 # as an associative array. The first thing to do is to
263 # apply our "alias" shortcuts.
26487603.17ms my $realField = $field;
26587604.59ms if ( $Foswiki::Query::Node::aliases{$field} ) {
266 $realField = $Foswiki::Query::Node::aliases{$field};
267 }
26887602.51ms if ( $realField eq 'META:TOPICINFO' ) {
269
270 # Ensure the revision info is populated from the store
271 $data->getRevisionInfo();
272 }
273876030.7ms876029.7ms if ( $realField =~ s/^META:// ) {
# spent 29.7ms making 8760 calls to Foswiki::Meta::topic, avg 3µs/call
274 if ( $Foswiki::Query::Node::isArrayType{$realField} ) {
275
276 # Array type, have to use find
277 my @e = $data->find($realField);
278 $result = \@e;
279 }
280 else {
281 $result = $data->get($realField);
282 }
283 }
284 elsif ( $realField eq 'name' ) {
285
286 # Special accessor to compensate for lack of a topic
287 # name anywhere in the saved fields of meta
288 return $data->topic();
289 }
290 elsif ( $realField eq 'text' ) {
291
292 # Special accessor to compensate for lack of the topic text
293 # name anywhere in the saved fields of meta
294 return $data->text();
295 }
296 elsif ( $realField eq 'web' ) {
297
298 # Special accessor to compensate for lack of a web
299 # name anywhere in the saved fields of meta
300 return $data->web();
301 }
302 elsif ( $data->topic() ) {
303
304 # The field name isn't an alias, check to see if it's
305 # the form name
306876013.8ms876095.0ms my $form = $data->get('FORM');
# spent 95.0ms making 8760 calls to Foswiki::Meta::get, avg 11µs/call
307876013.0ms if ( $form && $field eq $form->{name} ) {
308
309 # SHORTCUT;it's the form name, so give me the fields
310 # as if the 'field' keyword had been used.
311 # TODO: This is where multiple form support needs to reside.
312 # Return the array of FIELD for further indexing.
313 my @e = $data->find('FIELD');
314 return \@e;
315 }
316 else {
317
318 # SHORTCUT; not a predefined name; assume it's a field
319 # 'name' instead.
320 # SMELL: Needs to error out if there are multiple forms -
321 # or perhaps have a heuristic that gives access to the
322 # uniquely named field.
323876014.0ms876082.3ms $result = $data->get( 'FIELD', $field );
# spent 82.3ms making 8760 calls to Foswiki::Meta::get, avg 9µs/call
324876013.3ms $result = $result->{value} if $result;
325 }
326 }
327 }
328 elsif ( ref($data) eq 'ARRAY' ) {
329
330 # Array objects are returned during evaluation, e.g. when
331 # a subset of an array is matched for further processing.
332
333 # Indexing an array object. The index will be one of:
334 # 1. An integer, which is an implicit index='x' query
335 # 2. A name, which is an implicit name='x' query
336 if ( $field =~ /^\d+$/ ) {
337
338 # Integer index
339 $result = $data->[$field];
340 }
341 else {
342
343 # String index
344 my @res;
345
346 # Get all array entries that match the field
347 foreach my $f (@$data) {
348 my $val = getField( undef, $node, $f, $field );
349 push( @res, $val ) if defined($val);
350 }
351 if ( scalar(@res) ) {
352 $result = \@res;
353 }
354 else {
355
356 # The field name wasn't explicitly seen in any of the records.
357 # Try again, this time matching 'name' and returning 'value'
358 foreach my $f (@$data) {
359 next unless ref($f) eq 'HASH';
360 if ( $f->{name}
361 && $f->{name} eq $field
362 && defined $f->{value} )
363 {
364 push( @res, $f->{value} );
365 }
366 }
367 if ( scalar(@res) ) {
368 $result = \@res;
369 }
370 }
371 }
372 }
373 elsif ( ref($data) eq 'HASH' ) {
374
375 # A hash object may be returned when a sub-object of a Foswiki::Meta
376 # object has been matched.
377 $result = $data->{ $node->{params}[0] };
378 }
379 else {
380 $result = $node->{params}[0];
381 }
382876052.1ms return $result;
383}
384
385# Get a referenced topic
386# See Foswiki::Store::QueryAlgorithms.pm for details
387sub getRefTopic {
388 my ( $this, $relativeTo, $w, $t ) = @_;
389 return Foswiki::Meta->load( $relativeTo->session, $w, $t );
390}
391
39212µs1;
393__END__