Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/Query/Node.pm |
Statements | Executed 1894 statements in 11.9ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
150 | 8 | 7 | 5.17ms | 28.5ms | evaluate (recurses: max depth 2, inclusive time 16.1ms) | Foswiki::Query::Node::
115 | 3 | 1 | 2.78ms | 6.68ms | newLeaf | Foswiki::Query::Node::
1 | 1 | 1 | 739µs | 1.65ms | BEGIN@75 | Foswiki::Query::Node::
60 | 1 | 1 | 201µs | 201µs | CORE:match (opcode) | Foswiki::Query::Node::
22 | 1 | 1 | 123µs | 123µs | tokens | Foswiki::Query::Node::
2 | 2 | 2 | 70µs | 288µs | simplify | Foswiki::Query::Node::
2 | 1 | 1 | 59µs | 127µs | _freeze | Foswiki::Query::Node::
3 | 2 | 2 | 35µs | 35µs | evaluatesToConstant | Foswiki::Query::Node::
1 | 1 | 1 | 26µs | 33µs | BEGIN@29 | Foswiki::Query::Node::
1 | 1 | 1 | 21µs | 64µs | BEGIN@93 | Foswiki::Query::Node::
1 | 1 | 1 | 17µs | 35µs | BEGIN@30 | Foswiki::Query::Node::
1 | 1 | 1 | 16µs | 54µs | BEGIN@34 | Foswiki::Query::Node::
1 | 1 | 1 | 16µs | 374µs | BEGIN@35 | Foswiki::Query::Node::
1 | 1 | 1 | 16µs | 68µs | BEGIN@109 | Foswiki::Query::Node::
1 | 1 | 1 | 15µs | 108µs | BEGIN@41 | Foswiki::Query::Node::
1 | 1 | 1 | 15µs | 103µs | BEGIN@42 | Foswiki::Query::Node::
1 | 1 | 1 | 10µs | 10µs | BEGIN@37 | Foswiki::Query::Node::
1 | 1 | 1 | 10µs | 10µs | BEGIN@31 | Foswiki::Query::Node::
1 | 1 | 1 | 4µs | 4µs | isEmpty | Foswiki::Query::Node::
0 | 0 | 0 | 0s | 0s | _getField | Foswiki::Query::Node::
0 | 0 | 0 | 0s | 0s | _makeArray | Foswiki::Query::Node::
0 | 0 | 0 | 0s | 0s | emptyExpression | Foswiki::Query::Node::
0 | 0 | 0 | 0s | 0s | toString | Foswiki::Query::Node::
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::Query::Node | ||||
6 | |||||
7 | A Node object is a single node in a query (either a tree node or a leaf node). | ||||
8 | A tree of node objects represents a query over the Foswiki database. | ||||
9 | |||||
10 | Fields are given by name, and values by strings or numbers. | ||||
11 | |||||
12 | A query object implements the =evaluate= method as its general | ||||
13 | contract with the rest of the world. This method is a "reference implementation" - | ||||
14 | it does a brute force evaluation of the expression represented by the node in a given | ||||
15 | data domain. It is expected that smarter store implementations will analyse the parse tree | ||||
16 | and derive as many optimisations as possible, minimising fallback to this brute force | ||||
17 | evaluation. | ||||
18 | |||||
19 | The reference implementation of evaluation uses the =getField= method in the | ||||
20 | {Store}{QueryAlgorithm} to get data from the store. This further decouples the query | ||||
21 | object from the detail of the store implementation. | ||||
22 | |||||
23 | See Foswiki::Store::QueryAlgorithms for a full spec of the interface to | ||||
24 | query algorithms. | ||||
25 | |||||
26 | =cut | ||||
27 | |||||
28 | package Foswiki::Query::Node; | ||||
29 | 2 | 51µs | 2 | 41µs | # spent 33µs (26+8) within Foswiki::Query::Node::BEGIN@29 which was called:
# once (26µs+8µs) by Foswiki::Infix::Node::BEGIN@124 at line 29 # spent 33µs making 1 call to Foswiki::Query::Node::BEGIN@29
# spent 8µs making 1 call to strict::import |
30 | 2 | 43µs | 2 | 53µs | # spent 35µs (17+18) within Foswiki::Query::Node::BEGIN@30 which was called:
# once (17µs+18µs) by Foswiki::Infix::Node::BEGIN@124 at line 30 # spent 35µs making 1 call to Foswiki::Query::Node::BEGIN@30
# spent 18µs making 1 call to warnings::import |
31 | 2 | 59µs | 1 | 10µs | # spent 10µs within Foswiki::Query::Node::BEGIN@31 which was called:
# once (10µs+0s) by Foswiki::Infix::Node::BEGIN@124 at line 31 # spent 10µs making 1 call to Foswiki::Query::Node::BEGIN@31 |
32 | 1 | 10µs | our @ISA = ('Foswiki::Infix::Node'); | ||
33 | |||||
34 | 2 | 47µs | 2 | 92µs | # spent 54µs (16+38) within Foswiki::Query::Node::BEGIN@34 which was called:
# once (16µs+38µs) by Foswiki::Infix::Node::BEGIN@124 at line 34 # spent 54µs making 1 call to Foswiki::Query::Node::BEGIN@34
# spent 38µs making 1 call to Assert::import |
35 | 2 | 48µs | 2 | 732µs | # spent 374µs (16+358) within Foswiki::Query::Node::BEGIN@35 which was called:
# once (16µs+358µs) by Foswiki::Infix::Node::BEGIN@124 at line 35 # spent 374µs making 1 call to Foswiki::Query::Node::BEGIN@35
# spent 358µs making 1 call to Error::import |
36 | |||||
37 | 2 | 46µs | 1 | 10µs | # spent 10µs within Foswiki::Query::Node::BEGIN@37 which was called:
# once (10µs+0s) by Foswiki::Infix::Node::BEGIN@124 at line 37 # spent 10µs making 1 call to Foswiki::Query::Node::BEGIN@37 |
38 | |||||
39 | # <DEBUG SUPPORT> | ||||
40 | |||||
41 | 2 | 47µs | 2 | 200µs | # spent 108µs (15+92) within Foswiki::Query::Node::BEGIN@41 which was called:
# once (15µs+92µs) by Foswiki::Infix::Node::BEGIN@124 at line 41 # spent 108µs making 1 call to Foswiki::Query::Node::BEGIN@41
# spent 93µs making 1 call to constant::import |
42 | 2 | 236µs | 2 | 190µs | # spent 103µs (15+87) within Foswiki::Query::Node::BEGIN@42 which was called:
# once (15µs+87µs) by Foswiki::Infix::Node::BEGIN@124 at line 42 # spent 103µs making 1 call to Foswiki::Query::Node::BEGIN@42
# spent 87µs making 1 call to constant::import |
43 | |||||
44 | # Cache of the names of $Foswiki::cfg items that are accessible | ||||
45 | 1 | 1µs | our $isAccessibleCfg; | ||
46 | |||||
47 | =begin TML | ||||
48 | |||||
49 | ---++ PUBLIC %aliases | ||||
50 | A hash mapping short aliases for META: entry names. For example, this hash | ||||
51 | maps 'form' to 'META:FORM'. Published because extensions (search | ||||
52 | implementations) have made use of it in the past, though not part of the | ||||
53 | offical API. | ||||
54 | |||||
55 | This hash is maintained by Foswiki::Meta and is *strictly read-only* | ||||
56 | |||||
57 | ---++ PUBLIC %isArrayType | ||||
58 | Maps META: entry type names to true if the type is an array type (such as | ||||
59 | FIELD, ATTACHMENT or PREFERENCE). Published because extensions (search | ||||
60 | implementations) have made use of it in the past, though not part of the | ||||
61 | offical API. The type name should be given without the leading 'META:' | ||||
62 | |||||
63 | This hash is maintained by Foswiki::Meta and is *strictly read-only* | ||||
64 | |||||
65 | =cut | ||||
66 | |||||
67 | # These used to be declared here, but have been refactored back into | ||||
68 | # Foswiki::Meta | ||||
69 | 1 | 2µs | *aliases = \%Foswiki::Meta::aliases; | ||
70 | 1 | 1µs | *isArrayType = \%Foswiki::Meta::isArrayType; | ||
71 | |||||
72 | 1 | 1µs | our $emptyExprOp; | ||
73 | 1 | 800ns | our $commaOp; | ||
74 | |||||
75 | # spent 1.65ms (739µs+915µs) within Foswiki::Query::Node::BEGIN@75 which was called:
# once (739µs+915µs) by Foswiki::Infix::Node::BEGIN@124 at line 80 | ||||
76 | 4 | 223µs | require Foswiki::Query::OP_empty; | ||
77 | 1 | 54µs | $emptyExprOp = Foswiki::Query::OP_empty->new(); # spent 54µs making 1 call to Foswiki::Query::OP_empty::new | ||
78 | require Foswiki::Query::OP_comma; | ||||
79 | 1 | 50µs | $commaOp = Foswiki::Query::OP_comma->new(); # spent 50µs making 1 call to Foswiki::Query::OP_comma::new | ||
80 | 1 | 106µs | 1 | 1.65ms | } # spent 1.65ms making 1 call to Foswiki::Query::Node::BEGIN@75 |
81 | |||||
82 | sub emptyExpression { | ||||
83 | my $this = shift; | ||||
84 | return $this->newNode($emptyExprOp); | ||||
85 | } | ||||
86 | |||||
87 | sub toString { | ||||
88 | my $a = shift; | ||||
89 | return 'undef' unless defined($a); | ||||
90 | |||||
91 | # Suppress the recursion check; the tree can easily be more than | ||||
92 | # 100 levels deep. | ||||
93 | 2 | 198µs | 2 | 108µs | # spent 64µs (21+43) within Foswiki::Query::Node::BEGIN@93 which was called:
# once (21µs+43µs) by Foswiki::Infix::Node::BEGIN@124 at line 93 # spent 64µs making 1 call to Foswiki::Query::Node::BEGIN@93
# spent 43µs making 1 call to warnings::unimport |
94 | if ( UNIVERSAL::isa( $a, 'Foswiki::Query::Node' ) ) { | ||||
95 | return | ||||
96 | '{ op => ' | ||||
97 | . $a->{op} | ||||
98 | . ', params => ' | ||||
99 | . toString( $a->{params} ) . ' }'; | ||||
100 | } | ||||
101 | if ( ref($a) eq 'ARRAY' ) { | ||||
102 | return '[' . join( ',', map { toString($_) } @$a ) . ']'; | ||||
103 | } | ||||
104 | if ( ref($a) eq 'HASH' ) { | ||||
105 | return | ||||
106 | '{' | ||||
107 | . join( ',', map { "$_=>" . toString( $a->{$_} ) } keys %$a ) . '}'; | ||||
108 | } | ||||
109 | 2 | 2.34ms | 2 | 121µs | # spent 68µs (16+52) within Foswiki::Query::Node::BEGIN@109 which was called:
# once (16µs+52µs) by Foswiki::Infix::Node::BEGIN@124 at line 109 # spent 68µs making 1 call to Foswiki::Query::Node::BEGIN@109
# spent 52µs making 1 call to warnings::import |
110 | if ( UNIVERSAL::isa( $a, 'Foswiki::Meta' ) ) { | ||||
111 | return $a->stringify(); | ||||
112 | } | ||||
113 | return $a; | ||||
114 | } | ||||
115 | |||||
116 | 1 | 2µs | my $ind = 0; | ||
117 | |||||
118 | # </DEBUG SUPPORT> | ||||
119 | |||||
120 | # STATIC overrides Foswiki::Infix::Node | ||||
121 | # We expand config vars to constant strings during the parse, because | ||||
122 | # otherwise we'd have to export the knowledge of config vars out to other | ||||
123 | # engines that may evaluate queries instead of the default evaluator. | ||||
124 | # spent 6.68ms (2.78+3.90) within Foswiki::Query::Node::newLeaf which was called 115 times, avg 58µs/call:
# 60 times (1.65ms+2.04ms) by Foswiki::Infix::Parser::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Infix/Parser.pm:299] at line 269 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Infix/Parser.pm, avg 62µs/call
# 54 times (1.11ms+1.80ms) by Foswiki::Infix::Parser::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Infix/Parser.pm:299] at line 253 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Infix/Parser.pm, avg 54µs/call
# once (23µs+63µs) by Foswiki::Infix::Parser::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Infix/Parser.pm:299] at line 261 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Infix/Parser.pm | ||||
125 | 408 | 2.99ms | my ( $class, $val, $type ) = @_; | ||
126 | |||||
127 | 60 | 201µs | if ( $type == Foswiki::Infix::Node::NAME # spent 201µs making 60 calls to Foswiki::Query::Node::CORE:match, avg 3µs/call | ||
128 | && $val =~ /^({[A-Z][A-Z0-9_]*})+$/i ) | ||||
129 | { | ||||
130 | |||||
131 | # config var name, make sure it's accessible. | ||||
132 | unless ( defined $isAccessibleCfg ) { | ||||
133 | $isAccessibleCfg = | ||||
134 | { map { $_ => 1 } @{ $Foswiki::cfg{AccessibleCFG} } }; | ||||
135 | } | ||||
136 | $val = | ||||
137 | ( $isAccessibleCfg->{$val} ) ? eval( '$Foswiki::cfg' . $val ) : ''; # spent 6µs executing statements in string eval | ||||
138 | 1 | 42µs | return $class->SUPER::newLeaf( $val, Foswiki::Infix::Node::STRING ); # spent 42µs making 1 call to Foswiki::Infix::Node::newLeaf | ||
139 | } | ||||
140 | else { | ||||
141 | 114 | 3.66ms | return $class->SUPER::newLeaf( $val, $type ); # spent 3.66ms making 114 calls to Foswiki::Infix::Node::newLeaf, avg 32µs/call | ||
142 | } | ||||
143 | } | ||||
144 | |||||
145 | =begin TML | ||||
146 | |||||
147 | ---++ ObjectMethod evaluate(...) -> $result | ||||
148 | |||||
149 | Evaluate this node by invoking the =evaluate= method of the attached operator. | ||||
150 | The return result is either an array ref (for many results) or a scalar (for a | ||||
151 | single result) | ||||
152 | |||||
153 | This is the reference evaluator for queries. However it may not be the only | ||||
154 | engine that evaluates them; external engines, such as SQL, might be delegated | ||||
155 | the responsibility of evaluating queries in a search context. | ||||
156 | |||||
157 | Name resolution depends on the context in which the name is used. A name | ||||
158 | on the LHS of the dot and where operators may only be a form name, or a META: | ||||
159 | name, referred to as a "restricted name". A name anywhere else can be | ||||
160 | a META: name, a field name, or one of the shortcuts (such as "web", "name" | ||||
161 | etc). Fields and forms are looked up by calling the =getField= and | ||||
162 | =getForm= methods in the query engine respectively. | ||||
163 | |||||
164 | =cut | ||||
165 | |||||
166 | # spent 28.5ms (5.17+23.3) within Foswiki::Query::Node::evaluate which was called 150 times, avg 190µs/call:
# 75 times (2.80ms+25.5ms) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/IF.pm:43] at line 35 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/IF.pm, avg 378µs/call
# 24 times (835µs+-835µs) by Foswiki::Query::OP_and::evaluate at line 35 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Query/OP_and.pm, avg 0s/call
# 22 times (666µs+-666µs) by Foswiki::Query::ConditionalOP::evalTest at line 69 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Query/ConditionalOP.pm, avg 0s/call
# 22 times (610µs+-610µs) by Foswiki::Query::ConditionalOP::evalTest at line 70 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Query/ConditionalOP.pm, avg 0s/call
# 3 times (106µs+-106µs) by Foswiki::Query::OP_or::evaluate at line 35 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Query/OP_or.pm, avg 0s/call
# 2 times (58µs+10µs) by Foswiki::Query::Node::simplify at line 348, avg 34µs/call
# once (54µs+9µs) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 81 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm
# once (41µs+7µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/QUERY.pm:56] at line 54 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/QUERY.pm | ||||
167 | 1400 | 5.19ms | my $this = shift; | ||
168 | 150 | 582µs | ASSERT( scalar(@_) % 2 == 0 ); # spent 582µs making 150 calls to Assert::dummyASSERT, avg 4µs/call | ||
169 | my $result; | ||||
170 | |||||
171 | print STDERR ( ' ' x $ind ) . $this->stringify() if MONITOR_EVAL; | ||||
172 | |||||
173 | if ( !ref( $this->{op} ) ) { | ||||
174 | my %domain = @_; | ||||
175 | if ( $this->{op} == Foswiki::Infix::Node::NAME | ||||
176 | && defined $domain{data} ) | ||||
177 | { | ||||
178 | print STDERR ' NAME' if MONITOR_EVAL; | ||||
179 | if ( lc( $this->{params}[0] ) eq 'now' ) { | ||||
180 | $result = time(); | ||||
181 | } | ||||
182 | elsif ( lc( $this->{params}[0] ) eq 'undefined' ) { | ||||
183 | $result = undef; | ||||
184 | } | ||||
185 | else { | ||||
186 | |||||
187 | # a name; either the form name or a field name. | ||||
188 | # Look it up in $domain{data} | ||||
189 | eval "require $Foswiki::cfg{Store}{QueryAlgorithm}"; | ||||
190 | if ($@) { | ||||
191 | print STDERR ' BOOM ' if MONITOR_EVAL; | ||||
192 | die $@; | ||||
193 | } | ||||
194 | my $name = $this->{params}[0]; | ||||
195 | my $realname = $Foswiki::Meta::aliases{$name} || $name; | ||||
196 | if ( $domain{restricted_name} && $realname !~ /^META:/ ) { | ||||
197 | |||||
198 | # Only a form name and META: expressions are | ||||
199 | # legal on the LHS of a dot or where expression | ||||
200 | print STDERR " form $name" if MONITOR_EVAL; | ||||
201 | $result = | ||||
202 | $Foswiki::cfg{Store}{QueryAlgorithm} | ||||
203 | ->getForm( $this, $domain{data}, $name ); | ||||
204 | } | ||||
205 | else { | ||||
206 | print STDERR " field $name" if MONITOR_EVAL; | ||||
207 | $name = $realname | ||||
208 | if UNIVERSAL::isa( $domain{data}, 'Foswiki::Meta' ); | ||||
209 | $result = $this->_getField( $domain{data}, $name ); | ||||
210 | } | ||||
211 | } | ||||
212 | } | ||||
213 | else { | ||||
214 | print STDERR ' constant' if MONITOR_EVAL; | ||||
215 | $result = $this->{params}[0]; | ||||
216 | } | ||||
217 | } | ||||
218 | else { | ||||
219 | print STDERR " {\n" if MONITOR_EVAL; | ||||
220 | $ind++ if MONITOR_EVAL; | ||||
221 | my %params = @_; | ||||
222 | delete $params{no_fields}; # kill semaphore | ||||
223 | 100 | 38.8ms | $result = $this->{op}->evaluate( $this, %params ); # spent 13.5ms making 15 calls to Foswiki::If::OP_dollar::evaluate, avg 899µs/call
# spent 6.47ms making 13 calls to Foswiki::Query::OP_and::evaluate, avg 498µs/call
# spent 6.31ms making 12 calls to Foswiki::Query::OP_ne::evaluate, avg 526µs/call
# spent 4.64ms making 10 calls to Foswiki::Query::OP_eq::evaluate, avg 464µs/call
# spent 2.29ms making 10 calls to Foswiki::If::OP_defined::evaluate, avg 229µs/call
# spent 1.92ms making 6 calls to Foswiki::If::OP_istopic::evaluate, avg 320µs/call
# spent 1.89ms making 1 call to Foswiki::Query::OP_or::evaluate
# spent 1.81ms making 33 calls to Foswiki::If::OP_context::evaluate, avg 55µs/call | ||
224 | $ind-- if MONITOR_EVAL; | ||||
225 | print STDERR ( ' ' x $ind ) . '}' . $this->{op}->{name} | ||||
226 | if MONITOR_EVAL; | ||||
227 | } | ||||
228 | if (MONITOR_EVAL) { | ||||
229 | print STDERR ' -> ' . toString($result); | ||||
230 | my %domain = @_; | ||||
231 | print STDERR " IN " . $domain{tom}->getPath() . "\n" | ||||
232 | if ref( $domain{tom} ) && !$ind; | ||||
233 | print STDERR "\n"; | ||||
234 | } | ||||
235 | return $result; | ||||
236 | } | ||||
237 | |||||
238 | # Private method to fetch field values | ||||
239 | sub _getField { | ||||
240 | my ( $this, $data, $name ) = @_; | ||||
241 | |||||
242 | if ( UNIVERSAL::isa( $data, 'Foswiki::Meta' ) ) { | ||||
243 | |||||
244 | # If the data is a Foswiki::Meta, pass on to the query algorithm | ||||
245 | return $Foswiki::cfg{Store}{QueryAlgorithm} | ||||
246 | ->getField( $this, $data, $name ); | ||||
247 | } | ||||
248 | |||||
249 | if ( ref($data) eq 'ARRAY' ) { | ||||
250 | |||||
251 | # Array objects are returned during evaluation, e.g. when | ||||
252 | # a subset of an array is matched for further processing. | ||||
253 | |||||
254 | # Indexing an array object. The index will be one of: | ||||
255 | # 1. An integer, which is an implicit index='x' query | ||||
256 | # 2. A name, which is an implicit name='x' query | ||||
257 | if ( $name =~ /^\d+$/ ) { | ||||
258 | |||||
259 | # Integer index | ||||
260 | return $data->[$name]; | ||||
261 | } | ||||
262 | |||||
263 | # String index | ||||
264 | my @res; | ||||
265 | |||||
266 | # Get all array entries that match the field | ||||
267 | foreach my $f (@$data) { | ||||
268 | my $val = $this->_getField( $f, $name ); | ||||
269 | push( @res, $val ) if defined($val); | ||||
270 | } | ||||
271 | return \@res if ( scalar(@res) ); | ||||
272 | |||||
273 | # The field name wasn't explicitly seen in any of the records. | ||||
274 | # Try again, this time matching 'name' and returning 'value' | ||||
275 | foreach my $f (@$data) { | ||||
276 | next unless ref($f) eq 'HASH'; | ||||
277 | if ( $f->{name} | ||||
278 | && $f->{name} eq $name | ||||
279 | && defined $f->{value} ) | ||||
280 | { | ||||
281 | push( @res, $f->{value} ); | ||||
282 | } | ||||
283 | } | ||||
284 | return \@res if ( scalar(@res) ); | ||||
285 | return undef; | ||||
286 | } | ||||
287 | |||||
288 | if ( ref($data) eq 'HASH' ) { | ||||
289 | |||||
290 | # A hash object may be returned when a sub-object of a Foswiki::Meta | ||||
291 | # object has been matched. | ||||
292 | return $data->{ $this->{params}[0] }; | ||||
293 | } | ||||
294 | |||||
295 | # Last ditch - treat it as a constant | ||||
296 | return $this->{params}[0]; | ||||
297 | } | ||||
298 | |||||
299 | =begin TML | ||||
300 | |||||
301 | ---++ ObjectMethod evaluatesToConstant(%opts) | ||||
302 | |||||
303 | Support for expression optimisation/hoisting. | ||||
304 | |||||
305 | Determine if this node evaluates to a constant or not. "Constant" is defined | ||||
306 | as "anything that doesn't involve actually looking in searched topics". | ||||
307 | This function takes the same parameters (%domain) as evaluate(). Note that | ||||
308 | no reference to the tom or data web or topic will be made, so you can | ||||
309 | simply pass an arbitrary Foswiki::Meta. | ||||
310 | |||||
311 | =cut | ||||
312 | |||||
313 | # spent 35µs within Foswiki::Query::Node::evaluatesToConstant which was called 3 times, avg 12µs/call:
# 2 times (24µs+0s) by Foswiki::Query::Node::simplify at line 347, avg 12µs/call
# once (11µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 74 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm | ||||
314 | 15 | 47µs | my $this = shift; | ||
315 | my $c = 0; | ||||
316 | if ( ref( $this->{op} ) ) { | ||||
317 | $c = $this->{op}->evaluatesToConstant( $this, @_ ); | ||||
318 | } | ||||
319 | elsif ( $this->{op} == Foswiki::Infix::Node::NUMBER ) { | ||||
320 | $c = 1; | ||||
321 | } | ||||
322 | elsif ( $this->{op} == Foswiki::Infix::Node::STRING ) { | ||||
323 | $c = 1; | ||||
324 | } | ||||
325 | print STDERR $this->stringify() . " is " | ||||
326 | . ( $c ? '' : 'not ' ) | ||||
327 | . "constant\n" | ||||
328 | if MONITOR_FOLD; | ||||
329 | return $c; | ||||
330 | } | ||||
331 | |||||
332 | =begin TML | ||||
333 | |||||
334 | ---++ ObjectMethod simplify(%opts) | ||||
335 | |||||
336 | Simplify the query by spotting constant expressions and evaluating them, | ||||
337 | replacing the constant expression with an atomic value in the expression tree. | ||||
338 | This function takes the same parameters (%domain) as evaluate(). Note that | ||||
339 | no reference to the tom or data web or topic will be made, so you can | ||||
340 | simply pass an arbitrary Foswiki::Meta. | ||||
341 | |||||
342 | =cut | ||||
343 | |||||
344 | # spent 288µs (70+218) within Foswiki::Query::Node::simplify which was called 2 times, avg 144µs/call:
# once (44µs+134µs) by Foswiki::Store::Interfaces::QueryAlgorithm::query at line 87 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm
# once (27µs+85µs) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 72 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm | ||||
345 | 10 | 62µs | my $this = shift; | ||
346 | |||||
347 | 2 | 24µs | if ( $this->evaluatesToConstant(@_) ) { # spent 24µs making 2 calls to Foswiki::Query::Node::evaluatesToConstant, avg 12µs/call | ||
348 | 2 | 67µs | my $c = $this->evaluate(@_); # spent 67µs making 2 calls to Foswiki::Query::Node::evaluate, avg 34µs/call | ||
349 | $c = 0 unless defined $c; | ||||
350 | 2 | 127µs | $this->_freeze($c); # spent 127µs making 2 calls to Foswiki::Query::Node::_freeze, avg 63µs/call | ||
351 | } | ||||
352 | else { | ||||
353 | for my $f ( @{ $this->{params} } ) { | ||||
354 | if ( UNIVERSAL::can( $f, 'simplify' ) ) { | ||||
355 | $f->simplify(@_); | ||||
356 | } | ||||
357 | } | ||||
358 | } | ||||
359 | } | ||||
360 | |||||
361 | # spent 127µs (59+68) within Foswiki::Query::Node::_freeze which was called 2 times, avg 63µs/call:
# 2 times (59µs+68µs) by Foswiki::Query::Node::simplify at line 350, avg 63µs/call | ||||
362 | 6 | 55µs | my ( $this, $c ) = @_; | ||
363 | |||||
364 | 2 | 46µs | if ( ref($c) eq 'ARRAY' ) { # spent 46µs making 2 calls to Foswiki::Query::OP::isNumber, avg 23µs/call | ||
365 | $this->_makeArray($c); | ||||
366 | } | ||||
367 | elsif ( ref($c) eq 'HASH' ) { | ||||
368 | $this->convertToLeaf( Foswiki::Infix::Node::HASH, $c ); | ||||
369 | } | ||||
370 | elsif ( ref($c) eq 'Foswiki::Meta' ) { | ||||
371 | $this->convertToLeaf( Foswiki::Infix::Node::META, $c ); | ||||
372 | } | ||||
373 | elsif ( Foswiki::Query::OP::isNumber($c) ) { | ||||
374 | 2 | 22µs | $this->convertToLeaf( Foswiki::Infix::Node::NUMBER, $c ); # spent 22µs making 2 calls to Foswiki::Infix::Node::convertToLeaf, avg 11µs/call | ||
375 | } | ||||
376 | else { | ||||
377 | |||||
378 | #Item10703: can't convert a non-scalar to a STRING without further processing. | ||||
379 | if ( ref($c) eq '' ) { | ||||
380 | $this->convertToLeaf( Foswiki::Infix::Node::STRING, $c ); | ||||
381 | } | ||||
382 | else { | ||||
383 | print STDERR "_freeze" . ref($c) . "\n" if MONITOR_FOLD; | ||||
384 | } | ||||
385 | } | ||||
386 | } | ||||
387 | |||||
388 | sub _makeArray { | ||||
389 | my ( $this, $array ) = @_; | ||||
390 | if ( scalar(@$array) == 0 ) { | ||||
391 | $this->{op} = $emptyExprOp; | ||||
392 | } | ||||
393 | elsif ( scalar(@$array) == 1 ) { | ||||
394 | die unless defined $array->[0]; | ||||
395 | $this->_freeze( $array->[0] ); | ||||
396 | } | ||||
397 | else { | ||||
398 | $this->{op} = $commaOp; | ||||
399 | $this->{params}[0] = Foswiki::Query::Node->newNode($commaOp); | ||||
400 | $this->{params}[0]->_freeze( shift(@$array) ); | ||||
401 | $this->{params}[1] = Foswiki::Query::Node->newNode($commaOp); | ||||
402 | $this->{params}[1]->_freeze($array); | ||||
403 | } | ||||
404 | } | ||||
405 | |||||
406 | =begin TML | ||||
407 | |||||
408 | ---++ ObjectMethod tokens() -> [] | ||||
409 | Provided for compatibility with Foswiki::Search::Node | ||||
410 | |||||
411 | =cut | ||||
412 | |||||
413 | # spent 123µs within Foswiki::Query::Node::tokens which was called 22 times, avg 6µs/call:
# 22 times (123µs+0s) by Foswiki::Search::formatResults at line 943 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 6µs/call | ||||
414 | 22 | 124µs | return []; | ||
415 | } | ||||
416 | |||||
417 | =begin TML | ||||
418 | |||||
419 | ---++ ObjectMethod isEmpty() -> $boolean | ||||
420 | Provided for compatibility with Foswiki::Search::Node | ||||
421 | |||||
422 | =cut | ||||
423 | |||||
424 | # spent 4µs within Foswiki::Query::Node::isEmpty which was called:
# once (4µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::query at line 77 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm | ||||
425 | 1 | 10µs | return 0; | ||
426 | } | ||||
427 | |||||
428 | 1 | 8µs | 1; | ||
429 | __END__ | ||||
# spent 201µs within Foswiki::Query::Node::CORE:match which was called 60 times, avg 3µs/call:
# 60 times (201µs+0s) by Foswiki::Query::Node::newLeaf at line 127, avg 3µs/call |