Merge lp:~zorba-coders/zorba/caching into lp:zorba
- caching
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~zorba-coders/zorba/caching |
Merge into: | lp:zorba |
Diff against target: |
1103 lines (+643/-39) 24 files modified
ChangeLog (+2/-0) doc/zorba/options.dox (+21/-0) include/zorba/pregenerated/diagnostic_list.h (+6/-0) modules/com/zorba-xquery/www/modules/pregenerated/errors.xq (+4/-0) modules/com/zorba-xquery/www/modules/pregenerated/warnings.xq (+20/-1) src/annotations/annotations.cpp (+7/-1) src/annotations/annotations.h (+2/-0) src/compiler/codegen/plan_visitor.cpp (+5/-1) src/context/static_context_consts.h (+2/-0) src/diagnostics/diagnostic_en.xml (+35/-0) src/diagnostics/pregenerated/diagnostic_list.cpp (+9/-0) src/diagnostics/pregenerated/dict_en.cpp (+7/-0) src/functions/udf.cpp (+211/-5) src/functions/udf.h (+19/-0) src/runtime/core/fncall_iterator.cpp (+161/-30) src/runtime/core/fncall_iterator.h (+33/-0) src/runtime/visitors/printer_visitor_impl.cpp (+17/-1) src/store/api/index.h (+12/-0) src/store/naive/simple_index_general.cpp (+14/-0) src/store/naive/simple_index_general.h (+2/-0) src/store/naive/simple_store.cpp (+3/-0) test/rbkt/ExpCompilerResults/IterPlan/zorba/udf/udf-fib-rec.iter (+42/-0) test/rbkt/ExpQueryResults/zorba/udf/udf-fib-rec.xml.res (+1/-0) test/rbkt/Queries/zorba/udf/udf-fib-rec.xq (+8/-0) |
To merge this branch: | bzr merge lp:~zorba-coders/zorba/caching |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Matthias Brantner | Approve | ||
Markos Zaharioudakis | Pending | ||
Review via email: mp+82787@code.launchpad.net |
This proposal supersedes a proposal from 2011-11-17.
This proposal has been superseded by a proposal from 2011-12-09.
Commit message
- automatic caching of recursive, non-sequential, and deterministic functions with atomic parameter and return types
- %ann:cache and %ann:no-cache for controlling function result caching
Description of the change
- automatic caching of recursive, non-sequential, and deterministic functions with atomic parameter and return types
- %ann:cache and %ann:no-cache for controlling function result caching
Zorba Build Bot (zorba-buildbot) wrote : Posted in a previous version of this proposal | # |
Zorba Build Bot (zorba-buildbot) wrote : Posted in a previous version of this proposal | # |
The attempt to merge lp:~matthias-brantner/zorba/caching into lp:zorba failed. Below is the output from the failed tests.
CMake Error at /home/ceej/
Validation queue job caching-
final status was:
31 tests did not succeed - changes not commited.
Error in read script: /home/ceej/
Markos Zaharioudakis (markos-za) wrote : Posted in a previous version of this proposal | # |
Here are a few problems I can see so far:
1. I don't think we can do function caching for variadic functions. The current implementation of user_function:
2. The user_function:
3. In UDFunctionCallI
lSpec.
is not correct if the type of the param is a user-defined type (because the store will not understand its name). You must call getBaseBuiltinT
4. It's probably worthwhile to do something so that we don't have to recompute the args in case of a cache miss. What we have to do is create a temp sequence for each arg, and fill it with the corresponding arg value; then bind the arg reference to that temp seq, instead the arg wrapper.
5. It's probably worthwhile to allow subtypes of xs:anyAtomicType? as param types. Index creation already supports "null" keys, but we will need a new probe function. This we should probably do as a phase-2 task.
Matthias Brantner (matthias-brantner) wrote : Posted in a previous version of this proposal | # |
Adressed comments 1-4.
Matthias Brantner (matthias-brantner) : Posted in a previous version of this proposal | # |
Zorba Build Bot (zorba-buildbot) wrote : Posted in a previous version of this proposal | # |
There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.
Zorba Build Bot (zorba-buildbot) wrote : | # |
Validation queue starting for merge proposal.
Log at: http://
Zorba Build Bot (zorba-buildbot) wrote : | # |
The attempt to merge lp:~matthias-brantner/zorba/caching into lp:zorba failed. Below is the output from the failed tests.
CMake Error at /home/ceej/
Validation queue job caching-
final status was:
3 tests did not succeed - changes not commited.
Error in read script: /home/ceej/
Markos Zaharioudakis (markos-za) wrote : | # |
Matthias, can you change the ownership to zorba-coders so that I can do some small changes (documentation and style)?
Markos Zaharioudakis (markos-za) wrote : | # |
I think there is a bug in user_function:
Matthias Brantner (matthias-brantner) : | # |
Zorba Build Bot (zorba-buildbot) wrote : | # |
Attempt to merge into lp:zorba failed due to conflicts:
text conflict in ChangeLog
text conflict in src/context/
- 10540. By Matthias Brantner
-
merge with trunk
- 10541. By Matthias Brantner
-
merge with trunk
- 10542. By Matthias Brantner
-
merge
Unmerged revisions
Preview Diff
1 | === modified file 'ChangeLog' |
2 | --- ChangeLog 2011-11-16 04:00:29 +0000 |
3 | +++ ChangeLog 2011-11-19 17:32:30 +0000 |
4 | @@ -54,6 +54,8 @@ |
5 | xs:anyAtomicType or xs:untypedAtomic. |
6 | * Added undo for node revalidation |
7 | * Optimization for count(collection()) expressions |
8 | + * Caching of results for recursive functions with atomic parameter and return types. |
9 | + * Added %ann:cache and %ann:no-cache to enable or disable caching of results of functions with atomic parameter and return types. |
10 | * Fixed bug #867133 (SWIG PHP build failure on Mac OSX) |
11 | * Fixed bug #872796 (validate-in-place can interfere with other update primitives) |
12 | * Fixed bug #872799 (validate-in-place can set incorrect types) |
13 | |
14 | === modified file 'doc/zorba/options.dox' |
15 | --- doc/zorba/options.dox 2011-09-14 06:15:19 +0000 |
16 | +++ doc/zorba/options.dox 2011-11-19 17:32:30 +0000 |
17 | @@ -278,6 +278,27 @@ |
18 | In order to be able to use the value twice, the <tt>string:materialize</tt> function must be used to materialize the entire contents of the file <tt>myfile.txt</tt> in memory. |
19 | Otherwise, the error zerr:ZSTR0055 is raised. |
20 | |
21 | +\paragraph caching_annotation Caching Results of Functions |
22 | +Caching of function results might improve the performance if computational expensive functions are invoked multiple times with the same arguments. |
23 | + |
24 | +Zorba automatically caches results of recursive, deterministic, and non-sequential functions whose parameter and return types are subtypes of xs:anyAtomicType if at least optimization level O1 is used. |
25 | +Specifically, if such a function is called twice with the same arguments, the result of the second call will return the same value without re-evaluating the function. |
26 | + |
27 | +For example, in the following recursive function computing a fibonacci number, each result is automatically cached and, hence, dramatically improves the performance. |
28 | + |
29 | +\include zorba/udf/udf-fib-rec.xq |
30 | + |
31 | +Specifically, this optimization reduces the complexity of the function from O(1.6^n) to O(n). |
32 | + |
33 | +In order to explicitly disable function caching, the user can specify the <tt>%ann:no-cache</tt> annotation. |
34 | + |
35 | +In addition, the user can use the <tt>%ann:cache</tt> annotation to cache the results of functions other than the ones that are automatically cached. |
36 | +However, this will only work if the function is not updating and its parameter and return types are subtypes of xs:anyAtomicType. |
37 | +Zorba will raise a warning if caching is explicitly enabled but the function does not meet this criteria (zwarn:ZWST0005). |
38 | + |
39 | +Please note, that explicitly enforcing caching for sequential or nondeterministic functions might not give the intended result. |
40 | +In such cases, Zorba will raise a warning (zwarn:ZWST0006). |
41 | + |
42 | \paragraph collection_index_annotations Annotations on Collections and Indexes |
43 | |
44 | The \ref xqddf uses annotations to assign properties to collections and indexes. |
45 | |
46 | === modified file 'include/zorba/pregenerated/diagnostic_list.h' |
47 | --- include/zorba/pregenerated/diagnostic_list.h 2011-11-15 08:23:20 +0000 |
48 | +++ include/zorba/pregenerated/diagnostic_list.h 2011-11-19 17:32:30 +0000 |
49 | @@ -600,6 +600,8 @@ |
50 | |
51 | extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZDDY0034_INDEX_RANGE_VALUE_PROBE_BAD_KEY_TYPES; |
52 | |
53 | +extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZDDY0035_INDEX_GENERAL_INSERT; |
54 | + |
55 | extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZDDY0031_IC_NOT_DECLARED; |
56 | |
57 | extern ZORBA_DLL_PUBLIC ZorbaErrorCode ZDDY0032_IC_NOT_ACTIVATED; |
58 | @@ -752,6 +754,10 @@ |
59 | |
60 | extern ZORBA_DLL_PUBLIC ZorbaWarningCode ZWST0004_AMBIGUOUS_SEQUENTIAL_FLWOR; |
61 | |
62 | +extern ZORBA_DLL_PUBLIC ZorbaWarningCode ZWST0005_CACHING_NOT_POSSIBLE; |
63 | + |
64 | +extern ZORBA_DLL_PUBLIC ZorbaWarningCode ZWST0006_CACHING_MIGHT_NOT_BE_INTENDED; |
65 | + |
66 | } // namespace zwarn |
67 | } // namespace zorba |
68 | #endif /* ZORBA_DIAGNOSTIC_LIST_API_H */ |
69 | |
70 | === modified file 'modules/com/zorba-xquery/www/modules/pregenerated/errors.xq' |
71 | --- modules/com/zorba-xquery/www/modules/pregenerated/errors.xq 2011-11-15 08:23:20 +0000 |
72 | +++ modules/com/zorba-xquery/www/modules/pregenerated/errors.xq 2011-11-19 17:32:30 +0000 |
73 | @@ -501,6 +501,10 @@ |
74 | |
75 | (:~ |
76 | :) |
77 | +declare variable $zerr:ZDDY0035 as xs:QName := fn:QName($zerr:NS, "zerr:ZDDY0035"); |
78 | + |
79 | +(:~ |
80 | +:) |
81 | declare variable $zerr:ZDDY0031 as xs:QName := fn:QName($zerr:NS, "zerr:ZDDY0031"); |
82 | |
83 | (:~ |
84 | |
85 | === modified file 'modules/com/zorba-xquery/www/modules/pregenerated/warnings.xq' |
86 | --- modules/com/zorba-xquery/www/modules/pregenerated/warnings.xq 2011-11-15 08:10:49 +0000 |
87 | +++ modules/com/zorba-xquery/www/modules/pregenerated/warnings.xq 2011-11-19 17:32:30 +0000 |
88 | @@ -53,4 +53,23 @@ |
89 | |
90 | (:~ |
91 | :) |
92 | -declare variable $zwarn:ZWST0004 as xs:QName := fn:QName($zwarn:NS, "zwarn:ZWST0004"); |
93 | \ No newline at end of file |
94 | +declare variable $zwarn:ZWST0004 as xs:QName := fn:QName($zwarn:NS, "zwarn:ZWST0004"); |
95 | + |
96 | +(:~ |
97 | + : |
98 | + : This warning is raised if the user explicitly enables caching |
99 | + : of function results (using the %ann:cache annotation) but the function |
100 | + : is updating or its parameter and return types are not subtypes of |
101 | + : xs:anyAtomicType. |
102 | + : |
103 | +:) |
104 | +declare variable $zwarn:ZWST0005 as xs:QName := fn:QName($zwarn:NS, "zwarn:ZWST0005"); |
105 | + |
106 | +(:~ |
107 | + : |
108 | + : This warning is raised if the user explicitly enables caching |
109 | + : of function results (using the %ann:cache annotation) and the function |
110 | + : is annotated as sequential or nondeterministic. |
111 | + : |
112 | +:) |
113 | +declare variable $zwarn:ZWST0006 as xs:QName := fn:QName($zwarn:NS, "zwarn:ZWST0006"); |
114 | \ No newline at end of file |
115 | |
116 | === modified file 'src/annotations/annotations.cpp' |
117 | --- src/annotations/annotations.cpp 2011-11-07 06:32:00 +0000 |
118 | +++ src/annotations/annotations.cpp 2011-11-19 17:32:30 +0000 |
119 | @@ -100,6 +100,9 @@ |
120 | |
121 | ZANN(streamable, streamable); |
122 | |
123 | + ZANN(cache, cache); |
124 | + ZANN(no-cache, nocache); |
125 | + |
126 | // |
127 | // Zorba annotations - xqddf |
128 | // |
129 | @@ -168,6 +171,10 @@ |
130 | ZANN(zann_nonsequential)); |
131 | |
132 | theRuleSet.push_back( |
133 | + ZANN(zann_cache) | |
134 | + ZANN(zann_nocache)); |
135 | + |
136 | + theRuleSet.push_back( |
137 | ZANN(fn_private) | |
138 | ZANN(fn_public)); |
139 | |
140 | @@ -433,6 +440,5 @@ |
141 | } |
142 | |
143 | |
144 | - |
145 | } /* namespace zorba */ |
146 | /* vim:set et sw=2 ts=2: */ |
147 | |
148 | === modified file 'src/annotations/annotations.h' |
149 | --- src/annotations/annotations.h 2011-11-01 13:47:10 +0000 |
150 | +++ src/annotations/annotations.h 2011-11-19 17:32:30 +0000 |
151 | @@ -55,6 +55,8 @@ |
152 | zann_nonassignable, |
153 | zann_sequential, |
154 | zann_nonsequential, |
155 | + zann_cache, |
156 | + zann_nocache, |
157 | zann_variadic, |
158 | zann_streamable, |
159 | zann_unique, |
160 | |
161 | === modified file 'src/compiler/codegen/plan_visitor.cpp' |
162 | --- src/compiler/codegen/plan_visitor.cpp 2011-10-24 02:42:07 +0000 |
163 | +++ src/compiler/codegen/plan_visitor.cpp 2011-11-19 17:32:30 +0000 |
164 | @@ -98,6 +98,7 @@ |
165 | #endif |
166 | |
167 | #include "functions/function.h" |
168 | +#include "functions/udf.h" |
169 | #include "functions/library.h" |
170 | |
171 | #include "types/typeops.h" |
172 | @@ -2283,11 +2284,14 @@ |
173 | dynamic_cast<EnclosedIterator*>(iter.getp())->setInUpdateExpr(); |
174 | } |
175 | } |
176 | -#if 0 |
177 | else if (func->isUdf()) |
178 | { |
179 | + // need to computeResultCaching here for iterprint to work |
180 | const user_function* udf = static_cast<const user_function*>(func); |
181 | + udf->computeResultCaching(theCCB->theXQueryDiagnostics); |
182 | + } |
183 | |
184 | +#if 0 |
185 | if (udf->isExiting()) |
186 | { |
187 | TypeManager* tm = v.get_type_manager(); |
188 | |
189 | === modified file 'src/context/static_context_consts.h' |
190 | --- src/context/static_context_consts.h 2011-07-21 23:02:27 +0000 |
191 | +++ src/context/static_context_consts.h 2011-11-19 17:32:30 +0000 |
192 | @@ -132,6 +132,8 @@ |
193 | zann_nonsequential, |
194 | zann_variadic, |
195 | zann_streamable, |
196 | + zann_cache, |
197 | + zann_no_cache, |
198 | zann_unique, |
199 | zann_nonunique, |
200 | zann_value_equality, |
201 | |
202 | === modified file 'src/diagnostics/diagnostic_en.xml' |
203 | --- src/diagnostics/diagnostic_en.xml 2011-11-15 08:23:20 +0000 |
204 | +++ src/diagnostics/diagnostic_en.xml 2011-11-19 17:32:30 +0000 |
205 | @@ -1997,6 +1997,10 @@ |
206 | <value>"$1": index range-value probe has search keys with incompatible types</value> |
207 | </diagnostic> |
208 | |
209 | + <diagnostic code="ZDDY0035" name="INDEX_GENERAL_INSERT"> |
210 | + <value>"$1": index inserting more than one key not allowed for general index</value> |
211 | + </diagnostic> |
212 | + |
213 | <diagnostic code="ZDDY0031" name="IC_NOT_DECLARED"> |
214 | <value>"$1": integrity constraint is not declared</value> |
215 | </diagnostic> |
216 | @@ -2307,6 +2311,37 @@ |
217 | <value>Sequential FLWOR expr may not have the semantics you expect</value> |
218 | </diagnostic> |
219 | |
220 | + <diagnostic code="ZWST0005" name="CACHING_NOT_POSSIBLE"> |
221 | + <comment> |
222 | + This warning is raised if the user explicitly enables caching |
223 | + of function results (using the %ann:cache annotation) but the function |
224 | + is updating or its parameter and return types are not subtypes of |
225 | + xs:anyAtomicType. |
226 | + </comment> |
227 | + <value>"$1": function caching not possible; $2</value> |
228 | + <entry key="RETURN_TYPE"> |
229 | + <value>return type ($3) is not subtype of xs:anyAtomicType</value> |
230 | + </entry> |
231 | + <entry key="PARAM_TYPE"> |
232 | + <value>type of parameter $3 is $4 which is not a subtype of xs:anyAtomicType</value> |
233 | + </entry> |
234 | + <entry key="UPDATING"> |
235 | + <value>function is updating</value> |
236 | + </entry> |
237 | + <entry key="VARIADIC"> |
238 | + <value>function is variadic</value> |
239 | + </entry> |
240 | + </diagnostic> |
241 | + |
242 | + <diagnostic code="ZWST0006" name="CACHING_MIGHT_NOT_BE_INTENDED"> |
243 | + <comment> |
244 | + This warning is raised if the user explicitly enables caching |
245 | + of function results (using the %ann:cache annotation) and the function |
246 | + is annotated as sequential or nondeterministic. |
247 | + </comment> |
248 | + <value>"$1": function caching might not give the intended result because the function is declared as $2</value> |
249 | + </diagnostic> |
250 | + |
251 | </namespace> |
252 | |
253 | <!--////////// Subvalues /////////////////////////////////////////////////--> |
254 | |
255 | === modified file 'src/diagnostics/pregenerated/diagnostic_list.cpp' |
256 | --- src/diagnostics/pregenerated/diagnostic_list.cpp 2011-11-15 08:23:20 +0000 |
257 | +++ src/diagnostics/pregenerated/diagnostic_list.cpp 2011-11-19 17:32:30 +0000 |
258 | @@ -879,6 +879,9 @@ |
259 | ZorbaErrorCode ZDDY0034_INDEX_RANGE_VALUE_PROBE_BAD_KEY_TYPES( "ZDDY0034" ); |
260 | |
261 | |
262 | +ZorbaErrorCode ZDDY0035_INDEX_GENERAL_INSERT( "ZDDY0035" ); |
263 | + |
264 | + |
265 | ZorbaErrorCode ZDDY0031_IC_NOT_DECLARED( "ZDDY0031" ); |
266 | |
267 | |
268 | @@ -1104,6 +1107,12 @@ |
269 | ZorbaWarningCode ZWST0004_AMBIGUOUS_SEQUENTIAL_FLWOR( "ZWST0004" ); |
270 | |
271 | |
272 | +ZorbaWarningCode ZWST0005_CACHING_NOT_POSSIBLE( "ZWST0005" ); |
273 | + |
274 | + |
275 | +ZorbaWarningCode ZWST0006_CACHING_MIGHT_NOT_BE_INTENDED( "ZWST0006" ); |
276 | + |
277 | + |
278 | } // namespace zwarn |
279 | |
280 | } // namespace zorba |
281 | |
282 | === modified file 'src/diagnostics/pregenerated/dict_en.cpp' |
283 | --- src/diagnostics/pregenerated/dict_en.cpp 2011-11-15 08:23:20 +0000 |
284 | +++ src/diagnostics/pregenerated/dict_en.cpp 2011-11-19 17:32:30 +0000 |
285 | @@ -297,6 +297,7 @@ |
286 | { "ZDDY0032", "\"$1\": integrity constraint is not activated" }, |
287 | { "ZDDY0033", "\"$1\": integrity constraint not met for collection \"$2\"" }, |
288 | { "ZDDY0034", "\"$1\": index range-value probe has search keys with incompatible types" }, |
289 | + { "ZDDY0035", "\"$1\": index inserting more than one key not allowed for general index" }, |
290 | { "ZDST0001", "\"$1\": collection already declared" }, |
291 | { "ZDST0002", "\"$1\": collection already imported into module \"$2\"" }, |
292 | { "ZDST0003", "\"$1\": collection declaration not allowed in main module" }, |
293 | @@ -359,6 +360,8 @@ |
294 | { "ZWST0002", "\"$1\": unknown or unsupported annotation" }, |
295 | { "ZWST0003", "\"$1\": function declared sequential, but has non-sequential body" }, |
296 | { "ZWST0004", "Sequential FLWOR expr may not have the semantics you expect" }, |
297 | + { "ZWST0005", "\"$1\": function caching not possible; $2" }, |
298 | + { "ZWST0006", "\"$1\": function caching might not give the intended result because the function is declared as $2" }, |
299 | { "ZXQD0001", "\"$1\": prefix not declared when calling function \"$2\" from $3" }, |
300 | { "ZXQD0002", "\"$1\": $2" }, |
301 | { "ZXQD0003", "inconsistent options to the parse-xml-fragment() function: $1" }, |
302 | @@ -663,6 +666,10 @@ |
303 | { "~XUST0002_UDF_2", "\"$2\": function declared updating but body is not updating or vacuous" }, |
304 | { "~ZDST0060_unknown_localname", "unknown localname ($3)" }, |
305 | { "~ZDST0060_unknown_namespace", "unknown namespace ($3)" }, |
306 | + { "~ZWST0005_PARAM_TYPE", "type of parameter $3 is $4 which is not a subtype of xs:anyAtomicType" }, |
307 | + { "~ZWST0005_RETURN_TYPE", "return type ($3) is not subtype of xs:anyAtomicType" }, |
308 | + { "~ZWST0005_UPDATING", "function is updating" }, |
309 | + { "~ZWST0005_VARIADIC", "function is variadic" }, |
310 | { "~ZXQD0004_NON_NEGATIVE", "given value must be non-negative ($2)" }, |
311 | { "~ZXQD0004_NOT_WITHIN_RANGE", "not within allowed range ($2)" }, |
312 | { "~ZXQP0004_TypeOps_is_in_scope_ForFunctionItemTypes", "TypeOps::is_in_scope() for function-item types" }, |
313 | |
314 | === modified file 'src/functions/udf.cpp' |
315 | --- src/functions/udf.cpp 2011-10-18 17:37:41 +0000 |
316 | +++ src/functions/udf.cpp 2011-11-19 17:32:30 +0000 |
317 | @@ -26,10 +26,15 @@ |
318 | #include "compiler/rewriter/framework/rewriter.h" |
319 | |
320 | #include "functions/udf.h" |
321 | +#include "annotations/annotations.h" |
322 | #include "functions/function_impl.h" |
323 | |
324 | +#include "diagnostics/xquery_warning.h" |
325 | + |
326 | #include "types/typeops.h" |
327 | |
328 | +#include "store/api/index.h" // needed for destruction of the cache |
329 | + |
330 | |
331 | namespace zorba |
332 | { |
333 | @@ -54,7 +59,10 @@ |
334 | theIsExiting(false), |
335 | theIsLeaf(true), |
336 | theIsOptimized(false), |
337 | - thePlanStateSize(0) |
338 | + thePlanStateSize(0), |
339 | + theCache(0), |
340 | + theCacheResults(false), |
341 | + theCacheComputed(false) |
342 | { |
343 | setFlag(FunctionConsts::isUDF); |
344 | resetFlag(FunctionConsts::isBuiltin); |
345 | @@ -318,7 +326,7 @@ |
346 | /******************************************************************************* |
347 | |
348 | ********************************************************************************/ |
349 | - PlanIter_t user_function::getPlan(CompilerCB* ccb, uint32_t& planStateSize) |
350 | +PlanIter_t user_function::getPlan(CompilerCB* ccb, uint32_t& planStateSize) |
351 | { |
352 | if (thePlan == NULL) |
353 | { |
354 | @@ -372,9 +380,207 @@ |
355 | /******************************************************************************* |
356 | |
357 | ********************************************************************************/ |
358 | -CODEGEN_DEF(user_function) |
359 | -{ |
360 | - return new UDFunctionCallIterator(aSctx, aLoc, aArgs, this); |
361 | +store::Index* user_function::getCache() const |
362 | +{ |
363 | + return theCache; |
364 | +} |
365 | + |
366 | + |
367 | +/******************************************************************************* |
368 | + |
369 | +********************************************************************************/ |
370 | +void user_function::setCache(store::Index* aCache) |
371 | +{ |
372 | + theCache = aCache; |
373 | +} |
374 | + |
375 | + |
376 | +/******************************************************************************* |
377 | +********************************************************************************/ |
378 | +bool user_function::cacheResults() const |
379 | +{ |
380 | + return theCacheResults; |
381 | +} |
382 | + |
383 | + |
384 | +/******************************************************************************* |
385 | + only cache recursive (non-sequential, non-updating, deterministic) |
386 | + functions with singleton atomic input and output |
387 | +********************************************************************************/ |
388 | +void user_function::computeResultCaching(XQueryDiagnostics* diag) const |
389 | +{ |
390 | + if (theCacheComputed) |
391 | + { |
392 | + return; |
393 | + } |
394 | + |
395 | + struct OnExit { |
396 | + private: |
397 | + bool& theResult; |
398 | + bool& theCacheComputed; |
399 | + |
400 | + public: |
401 | + OnExit(bool& aResult, bool& aCacheComputed) |
402 | + : theResult(aResult), |
403 | + theCacheComputed(aCacheComputed) {} |
404 | + |
405 | + void cache() { theResult = true; } |
406 | + |
407 | + ~OnExit() |
408 | + { |
409 | + theCacheComputed = true; |
410 | + } |
411 | + }; |
412 | + |
413 | + // will be destroyed when the function is exited |
414 | + // set caching to true if cache() is called |
415 | + OnExit lExit(theCacheResults, theCacheComputed); |
416 | + |
417 | + // check necessary conditions |
418 | + // %ann:cache or not %ann:no-cache |
419 | + if (theAnnotationList && theAnnotationList->contains(AnnotationInternal::zann_nocache)) |
420 | + { |
421 | + return; |
422 | + } |
423 | + |
424 | + // was the %ann:cache annotation given explicitly by the user |
425 | + bool lExplicitCacheRequest = theAnnotationList |
426 | + ?theAnnotationList->contains(AnnotationInternal::zann_cache) |
427 | + :false; |
428 | + |
429 | + if (isVariadic()) |
430 | + { |
431 | + if (lExplicitCacheRequest) |
432 | + { |
433 | + diag->add_warning( |
434 | + NEW_XQUERY_WARNING( |
435 | + zwarn::ZWST0005_CACHING_NOT_POSSIBLE, |
436 | + WARN_PARAMS( |
437 | + getName()->getStringValue(), |
438 | + ZED( ZWST0005_VARIADIC ) |
439 | + ), |
440 | + WARN_LOC(theLoc) |
441 | + ) |
442 | + ); |
443 | + } |
444 | + return; |
445 | + } |
446 | + |
447 | + // parameter and return types are subtype of xs:anyAtomicType? |
448 | + const xqtref_t& lRes = theSignature.returnType(); |
449 | + TypeManager* tm = lRes->get_manager(); |
450 | + |
451 | + if (!TypeOps::is_subtype(tm, |
452 | + *lRes, |
453 | + *GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_ONE, |
454 | + theLoc)) |
455 | + { |
456 | + if (lExplicitCacheRequest) |
457 | + { |
458 | + diag->add_warning( |
459 | + NEW_XQUERY_WARNING( |
460 | + zwarn::ZWST0005_CACHING_NOT_POSSIBLE, |
461 | + WARN_PARAMS( |
462 | + getName()->getStringValue(), |
463 | + ZED( ZWST0005_RETURN_TYPE ), |
464 | + lRes->toString() |
465 | + ), |
466 | + WARN_LOC(theLoc) |
467 | + ) |
468 | + ); |
469 | + } |
470 | + return; |
471 | + } |
472 | + |
473 | + size_t lArity = theSignature.paramCount(); |
474 | + for (size_t i = 0; i < lArity; ++i) |
475 | + { |
476 | + const xqtref_t& lArg = theSignature[i]; |
477 | + if (!TypeOps::is_subtype(tm, |
478 | + *lArg, |
479 | + *GENV_TYPESYSTEM.ANY_ATOMIC_TYPE_ONE, |
480 | + theLoc)) |
481 | + { |
482 | + if (lExplicitCacheRequest) |
483 | + { |
484 | + diag->add_warning( |
485 | + NEW_XQUERY_WARNING( |
486 | + zwarn::ZWST0005_CACHING_NOT_POSSIBLE, |
487 | + WARN_PARAMS( |
488 | + getName()->getStringValue(), |
489 | + ZED( ZWST0005_PARAM_TYPE ), |
490 | + i+1, |
491 | + lArg->toString() |
492 | + ), |
493 | + WARN_LOC(theLoc) |
494 | + ) |
495 | + ); |
496 | + } |
497 | + return; |
498 | + } |
499 | + } |
500 | + |
501 | + // function updating? |
502 | + if (isUpdating()) |
503 | + { |
504 | + if (lExplicitCacheRequest) |
505 | + { |
506 | + diag->add_warning( |
507 | + NEW_XQUERY_WARNING( |
508 | + zwarn::ZWST0005_CACHING_NOT_POSSIBLE, |
509 | + WARN_PARAMS( |
510 | + getName()->getStringValue(), |
511 | + ZED( ZWST0005_UPDATING ) |
512 | + ), |
513 | + WARN_LOC(theLoc) |
514 | + ) |
515 | + ); |
516 | + } |
517 | + return; |
518 | + } |
519 | + |
520 | + if (lExplicitCacheRequest) |
521 | + { |
522 | + if (isSequential() || !isDeterministic()) |
523 | + { |
524 | + if (lExplicitCacheRequest) |
525 | + { |
526 | + diag->add_warning( |
527 | + NEW_XQUERY_WARNING( |
528 | + zwarn::ZWST0006_CACHING_MIGHT_NOT_BE_INTENDED, |
529 | + WARN_PARAMS( |
530 | + getName()->getStringValue(), |
531 | + (isSequential()?"sequential":"non-deterministic") |
532 | + ), |
533 | + WARN_LOC(theLoc) |
534 | + ) |
535 | + ); |
536 | + } |
537 | + } |
538 | + lExit.cache(); |
539 | + return; |
540 | + } |
541 | + |
542 | + // optimization is prerequisite before invoking isRecursive |
543 | + if (!lExplicitCacheRequest && isOptimized() && !isRecursive()) |
544 | + { |
545 | + return; |
546 | + } |
547 | + |
548 | + lExit.cache(); |
549 | +} |
550 | + |
551 | +/******************************************************************************* |
552 | + |
553 | +********************************************************************************/ |
554 | +PlanIter_t user_function::codegen( |
555 | + CompilerCB* cb, |
556 | + static_context* sctx, |
557 | + const QueryLoc& loc, |
558 | + std::vector<PlanIter_t>& argv, |
559 | + AnnotationHolder& ann) const |
560 | +{ |
561 | + return new UDFunctionCallIterator(sctx, loc, argv, this); |
562 | } |
563 | |
564 | |
565 | |
566 | === modified file 'src/functions/udf.h' |
567 | --- src/functions/udf.h 2011-10-18 17:37:41 +0000 |
568 | +++ src/functions/udf.h 2011-11-19 17:32:30 +0000 |
569 | @@ -25,6 +25,12 @@ |
570 | namespace zorba |
571 | { |
572 | |
573 | + namespace store |
574 | + { |
575 | + class Index; |
576 | + typedef rchandle<Index> Index_t; |
577 | + } |
578 | + |
579 | |
580 | /******************************************************************************* |
581 | A udf with params $x1, $x2, ..., $xn and a body_expr is translated into a |
582 | @@ -102,6 +108,10 @@ |
583 | uint32_t thePlanStateSize; |
584 | std::vector<ArgVarRefs> theArgVarsRefs; |
585 | |
586 | + mutable store::Index_t theCache; |
587 | + mutable bool theCacheResults; |
588 | + mutable bool theCacheComputed; |
589 | + |
590 | public: |
591 | SERIALIZABLE_CLASS(user_function) |
592 | user_function(::zorba::serialization::Archiver& ar); |
593 | @@ -160,12 +170,21 @@ |
594 | |
595 | const std::vector<ArgVarRefs>& getArgVarsRefs() const; |
596 | |
597 | + store::Index* getCache() const; |
598 | + |
599 | + void setCache(store::Index* aCache); |
600 | + |
601 | + bool cacheResults() const; |
602 | + |
603 | PlanIter_t codegen( |
604 | CompilerCB* cb, |
605 | static_context* sctx, |
606 | const QueryLoc& loc, |
607 | std::vector<PlanIter_t>& argv, |
608 | AnnotationHolder& ann) const; |
609 | + |
610 | + void |
611 | + computeResultCaching(XQueryDiagnostics*) const; |
612 | }; |
613 | |
614 | |
615 | |
616 | === modified file 'src/runtime/core/fncall_iterator.cpp' |
617 | --- src/runtime/core/fncall_iterator.cpp 2011-10-30 00:18:34 +0000 |
618 | +++ src/runtime/core/fncall_iterator.cpp 2011-11-19 17:32:30 +0000 |
619 | @@ -48,6 +48,11 @@ |
620 | |
621 | #include "util/string_util.h" |
622 | |
623 | +#include "store/api/index.h" |
624 | +#include "store/api/store.h" |
625 | +#include "store/api/iterator_factory.h" |
626 | +#include "store/api/temp_seq.h" |
627 | + |
628 | #ifdef ZORBA_WITH_DEBUGGER |
629 | #include "debugger/debugger_commons.h" |
630 | |
631 | @@ -93,7 +98,8 @@ |
632 | thePlanState(NULL), |
633 | thePlanStateSize(0), |
634 | theLocalDCtx(NULL), |
635 | - thePlanOpen(false) |
636 | + thePlanOpen(false), |
637 | + theCache(0) |
638 | { |
639 | } |
640 | |
641 | @@ -153,6 +159,7 @@ |
642 | { |
643 | thePlan->reset(*thePlanState); |
644 | } |
645 | + theCacheHits.clear(); |
646 | } |
647 | |
648 | |
649 | @@ -198,6 +205,103 @@ |
650 | /******************************************************************************* |
651 | |
652 | ********************************************************************************/ |
653 | +bool UDFunctionCallIterator::isCached() const |
654 | +{ |
655 | + return theUDF->cacheResults(); |
656 | +} |
657 | + |
658 | +/******************************************************************************* |
659 | + |
660 | +********************************************************************************/ |
661 | +void UDFunctionCallIterator::createCache( |
662 | + PlanState& planState, |
663 | + UDFunctionCallIteratorState* state) |
664 | +{ |
665 | + store::Index_t lIndex = theUDF->getCache(); |
666 | + if (!lIndex && theUDF->cacheResults()) |
667 | + { |
668 | + const signature& sig = theUDF->getSignature(); |
669 | + |
670 | + csize numArgs = theChildren.size(); |
671 | + |
672 | + store::IndexSpecification lSpec; |
673 | + lSpec.theNumKeyColumns = numArgs; |
674 | + lSpec.theKeyTypes.resize(numArgs); |
675 | + lSpec.theCollations.resize(numArgs); |
676 | + lSpec.theIsTemp = true; |
677 | + lSpec.theIsUnique = true; |
678 | + for (csize i = 0; i < numArgs; ++i) |
679 | + { |
680 | + lSpec.theKeyTypes[i] = sig[i]->getBaseBuiltinType()->get_qname().getp(); |
681 | + } |
682 | + lIndex = GENV_STORE.createIndex(theUDF->getName(), lSpec, 0); |
683 | + theUDF->setCache(lIndex.getp()); // cache the cache in the function itself |
684 | + state->theCacheHits.reserve(theChildren.size()); |
685 | + } |
686 | + state->theCache = lIndex.getp(); |
687 | +} |
688 | + |
689 | + |
690 | +/******************************************************************************* |
691 | + |
692 | +********************************************************************************/ |
693 | +bool UDFunctionCallIterator::probeCache( |
694 | + PlanState& planState, |
695 | + UDFunctionCallIteratorState* state, |
696 | + store::Item_t& result, |
697 | + std::vector<store::Item_t>& aKey) const |
698 | +{ |
699 | + if (!state->theCache) |
700 | + return false; |
701 | + |
702 | + store::IndexCondition_t lCond = |
703 | + state->theCache->createCondition(store::IndexCondition::POINT_VALUE); |
704 | + |
705 | + std::vector<store::Iterator_t>::iterator lIter |
706 | + = state->theArgWrappers.begin(); |
707 | + for (; lIter != state->theArgWrappers.end(); ++lIter) |
708 | + { |
709 | + store::Iterator_t& argWrapper = (*lIter); |
710 | + store::Item_t lArg; |
711 | + if (argWrapper) // might be 0 if argument is not used |
712 | + { |
713 | + argWrapper->next(lArg); // guaranteed to have exactly one result |
714 | + } |
715 | + aKey.push_back(lArg); |
716 | + lCond->pushItem(lArg); |
717 | + } |
718 | + store::IndexProbeIterator_t lCacheHit = |
719 | + GENV_STORE.getIteratorFactory()->createIndexProbeIterator(state->theCache); |
720 | + lCacheHit->init(lCond); |
721 | + lCacheHit->open(); |
722 | + return lCacheHit->next(result); |
723 | +} |
724 | + |
725 | + |
726 | +/******************************************************************************* |
727 | + |
728 | +********************************************************************************/ |
729 | +void UDFunctionCallIterator::insertCacheEntry( |
730 | + UDFunctionCallIteratorState* state, |
731 | + std::vector<store::Item_t>& aKey, |
732 | + store::Item_t& aValue) const |
733 | +{ |
734 | + if (state->theCache) |
735 | + { |
736 | + std::auto_ptr<store::IndexKey> k(new store::IndexKey()); |
737 | + store::IndexKey* k2 = k.get(); |
738 | + k->theItems = aKey; |
739 | + store::Item_t lTmp = aValue; // insert will eventually transfer the Item_t |
740 | + if (!state->theCache->insert(k2, lTmp)) |
741 | + { |
742 | + k.release(); |
743 | + } |
744 | + } |
745 | +} |
746 | + |
747 | +/******************************************************************************* |
748 | + |
749 | +********************************************************************************/ |
750 | void UDFunctionCallIterator::openImpl(PlanState& planState, uint32_t& offset) |
751 | { |
752 | UDFunctionCallIteratorState* state; |
753 | @@ -229,6 +333,11 @@ |
754 | // the plan state (but not the state block) and dynamic context. |
755 | state->open(planState, theUDF); |
756 | |
757 | + // if the results of the function should be cached (prereq: atomic in and out) |
758 | + // this functions stores an index in the dynamic context that contains |
759 | + // the cached results. The name of the index is the name of the function. |
760 | + createCache(planState, state); |
761 | + |
762 | // Create a wrapper over each subplan that computes an argument expr, if the |
763 | // associated param is actually used anywhere in the function body. |
764 | csize numArgs = theChildren.size(); |
765 | @@ -301,6 +410,9 @@ |
766 | { |
767 | try |
768 | { |
769 | + std::vector<store::Item_t> lKey; |
770 | + bool lCacheHit; |
771 | + |
772 | UDFunctionCallIteratorState* state; |
773 | DEFAULT_STACK_INIT(UDFunctionCallIteratorState, state, planState); |
774 | |
775 | @@ -314,19 +426,29 @@ |
776 | state->thePlanOpen = true; |
777 | } |
778 | |
779 | - // Bind the args. |
780 | + // check if there is a cache and the result is already in the cache |
781 | + lCacheHit = probeCache(planState, state, result, lKey); |
782 | + |
783 | + // if not in the cache, we bind the arguments to the function |
784 | + if (!lCacheHit) |
785 | { |
786 | const std::vector<ArgVarRefs>& argsRefs = theUDF->getArgVarsRefs(); |
787 | - std::vector<ArgVarRefs>::const_iterator argsRefsIte = argsRefs.begin(); |
788 | - std::vector<ArgVarRefs>::const_iterator argsRefsEnd = argsRefs.end(); |
789 | - |
790 | - std::vector<store::Iterator_t>::iterator argWrapsIte = |
791 | - state->theArgWrappers.begin(); |
792 | - |
793 | - for (; argsRefsIte != argsRefsEnd; ++argsRefsIte, ++argWrapsIte) |
794 | + const std::vector<store::Iterator_t>& argWraps = state->theArgWrappers; |
795 | + for (size_t i = 0; i < argsRefs.size(); ++i) |
796 | { |
797 | - store::Iterator_t& argWrapper = (*argWrapsIte); |
798 | - const ArgVarRefs& argVarRefs = (*argsRefsIte); |
799 | + const ArgVarRefs& argVarRefs = argsRefs[i]; |
800 | + store::Iterator_t argWrapper; |
801 | + if (state->theCache) |
802 | + { |
803 | + std::vector<store::Item_t> lParam(1, lKey[i]); |
804 | + state->theCacheHits.push_back(GENV_STORE.createTempSeq(lParam)); |
805 | + argWrapper = state->theCacheHits.back()->getIterator(); |
806 | + argWrapper->open(); |
807 | + } |
808 | + else |
809 | + { |
810 | + argWrapper = argWraps[i]; |
811 | + } |
812 | ArgVarRefs::const_iterator argVarRefsIte = argVarRefs.begin(); |
813 | ArgVarRefs::const_iterator argVarRefsEnd = argVarRefs.end(); |
814 | |
815 | @@ -343,25 +465,34 @@ |
816 | } |
817 | } |
818 | |
819 | -#ifdef ZORBA_WITH_DEBUGGER |
820 | - DEBUGGER_PUSH_FRAME; |
821 | -#endif |
822 | - |
823 | - while (consumeNext(result, state->thePlan, *state->thePlanState)) |
824 | - { |
825 | -#ifdef ZORBA_WITH_DEBUGGER |
826 | - DEBUGGER_POP_FRAME; |
827 | -#endif |
828 | - STACK_PUSH(true, state); |
829 | - |
830 | -#ifdef ZORBA_WITH_DEBUGGER |
831 | - DEBUGGER_PUSH_FRAME; |
832 | -#endif |
833 | - } |
834 | - |
835 | -#ifdef ZORBA_WITH_DEBUGGER |
836 | - DEBUGGER_POP_FRAME; |
837 | -#endif |
838 | + if (lCacheHit) |
839 | + { |
840 | + STACK_PUSH(true, state); |
841 | + } |
842 | + else |
843 | + { |
844 | +#ifdef ZORBA_WITH_DEBUGGER |
845 | + DEBUGGER_PUSH_FRAME; |
846 | +#endif |
847 | + while (consumeNext(result, state->thePlan, *state->thePlanState)) |
848 | + { |
849 | +#ifdef ZORBA_WITH_DEBUGGER |
850 | + DEBUGGER_POP_FRAME; |
851 | +#endif |
852 | + |
853 | + insertCacheEntry(state, lKey, result); |
854 | + STACK_PUSH(true, state); |
855 | + |
856 | +#ifdef ZORBA_WITH_DEBUGGER |
857 | + DEBUGGER_PUSH_FRAME; |
858 | +#endif |
859 | + } |
860 | + |
861 | +#ifdef ZORBA_WITH_DEBUGGER |
862 | + DEBUGGER_POP_FRAME; |
863 | +#endif |
864 | + |
865 | + } |
866 | |
867 | STACK_END(state); |
868 | |
869 | |
870 | === modified file 'src/runtime/core/fncall_iterator.h' |
871 | --- src/runtime/core/fncall_iterator.h 2011-10-30 00:18:34 +0000 |
872 | +++ src/runtime/core/fncall_iterator.h 2011-11-19 17:32:30 +0000 |
873 | @@ -69,6 +69,19 @@ |
874 | the body. So, it is never the case that the arg expr will have more than one |
875 | consumers, and as a result we can bind all those V references to the same arg |
876 | wrapper. |
877 | + |
878 | + theCache: |
879 | + --------- |
880 | + Is an Index which is set in the state if caching for the invoked function |
881 | + should be done. The cache is owned by the UDF itself and shared across |
882 | + all function invocations. |
883 | + |
884 | + theCacheHits: |
885 | + ------------- |
886 | + If caching is used, this vector contains the results of all arguments |
887 | + of the function evaluation. It's used to bind the variables if the |
888 | + cache didn't give a result in order to avoid duplicate evaluation of |
889 | + the arguments. |
890 | ********************************************************************************/ |
891 | class UDFunctionCallIteratorState : public PlanIteratorState |
892 | { |
893 | @@ -79,6 +92,8 @@ |
894 | dynamic_context * theLocalDCtx; |
895 | bool thePlanOpen; |
896 | std::vector<store::Iterator_t> theArgWrappers; |
897 | + store::Index * theCache; |
898 | + std::vector<store::TempSeq_t> theCacheHits; |
899 | |
900 | UDFunctionCallIteratorState(); |
901 | |
902 | @@ -130,6 +145,8 @@ |
903 | |
904 | void setDynamic() { theIsDynamic = true; } |
905 | |
906 | + bool isCached() const; |
907 | + |
908 | void accept(PlanIterVisitor& v) const; |
909 | |
910 | void openImpl(PlanState& planState, uint32_t& offset); |
911 | @@ -139,6 +156,22 @@ |
912 | void closeImpl(PlanState& planState); |
913 | |
914 | bool nextImpl(store::Item_t& result, PlanState& planState) const; |
915 | + |
916 | +protected: |
917 | + void createCache( |
918 | + PlanState& planState, |
919 | + UDFunctionCallIteratorState* state); |
920 | + |
921 | + bool probeCache( |
922 | + PlanState& planState, |
923 | + UDFunctionCallIteratorState* state, |
924 | + store::Item_t& result, |
925 | + std::vector<store::Item_t>& aKey) const; |
926 | + |
927 | + void insertCacheEntry( |
928 | + UDFunctionCallIteratorState* state, |
929 | + std::vector<store::Item_t>& aKey, |
930 | + store::Item_t& aValue) const; |
931 | }; |
932 | |
933 | |
934 | |
935 | === modified file 'src/runtime/visitors/printer_visitor_impl.cpp' |
936 | --- src/runtime/visitors/printer_visitor_impl.cpp 2011-10-11 01:05:23 +0000 |
937 | +++ src/runtime/visitors/printer_visitor_impl.cpp 2011-11-19 17:32:30 +0000 |
938 | @@ -1209,7 +1209,23 @@ |
939 | |
940 | #undef TYPED_VAL_CMP |
941 | |
942 | - PRINTER_VISITOR_DEFINITION (UDFunctionCallIterator) |
943 | + void PrinterVisitor::beginVisit ( const UDFunctionCallIterator& a ) |
944 | + { |
945 | + thePrinter.startBeginVisit("UDFunctionCallIterator", ++theId); |
946 | + printCommons( &a, theId ); |
947 | + if (a.isCached()) |
948 | + { |
949 | + thePrinter.addAttribute("cached", "true"); |
950 | + } |
951 | + thePrinter.endBeginVisit( theId); |
952 | + } |
953 | + |
954 | + void PrinterVisitor::endVisit ( const UDFunctionCallIterator& ) |
955 | + { |
956 | + thePrinter.startEndVisit(); |
957 | + thePrinter.endEndVisit(); |
958 | + } |
959 | + |
960 | PRINTER_VISITOR_DEFINITION (ExtFunctionCallIterator) |
961 | PRINTER_VISITOR_DEFINITION (FnBooleanIterator) |
962 | PRINTER_VISITOR_DEFINITION (OrIterator) |
963 | |
964 | === modified file 'src/store/api/index.h' |
965 | --- src/store/api/index.h 2011-10-11 12:11:48 +0000 |
966 | +++ src/store/api/index.h 2011-11-19 17:32:30 +0000 |
967 | @@ -415,6 +415,18 @@ |
968 | * Returns all keys stored in this index |
969 | */ |
970 | virtual KeyIterator_t keys() const = 0; |
971 | + |
972 | + /** |
973 | + * Insert the given item in the value set of the given key. If the key is not |
974 | + * in the index already, then the key itself is inserted as well. Return true |
975 | + * if the key was already in the index, false otherwise |
976 | + * The index wil take the ownership of the key if it was not already in the |
977 | + * index. |
978 | + * |
979 | + * @error ZDDY0035 if a key with more than one item is inserted into |
980 | + * a general index |
981 | + */ |
982 | + virtual bool insert(store::IndexKey*& key, store::Item_t& item) = 0; |
983 | }; |
984 | |
985 | |
986 | |
987 | === modified file 'src/store/naive/simple_index_general.cpp' |
988 | --- src/store/naive/simple_index_general.cpp 2011-11-15 18:48:54 +0000 |
989 | +++ src/store/naive/simple_index_general.cpp 2011-11-19 17:32:30 +0000 |
990 | @@ -236,6 +236,20 @@ |
991 | /****************************************************************************** |
992 | |
993 | *******************************************************************************/ |
994 | +bool GeneralIndex::insert(store::IndexKey*& key, store::Item_t& value) |
995 | +{ |
996 | + if (key->size() != 1) |
997 | + { |
998 | + RAISE_ERROR_NO_LOC(zerr::ZDDY0035_INDEX_GENERAL_INSERT, |
999 | + ERROR_PARAMS(getName()->getStringValue())); |
1000 | + } |
1001 | + return insert((*key)[0], value); |
1002 | +} |
1003 | + |
1004 | + |
1005 | +/****************************************************************************** |
1006 | + |
1007 | +*******************************************************************************/ |
1008 | bool GeneralIndex::insert(store::Item_t& key, store::Item_t& node) |
1009 | { |
1010 | bool lossy = false; |
1011 | |
1012 | === modified file 'src/store/naive/simple_index_general.h' |
1013 | --- src/store/naive/simple_index_general.h 2011-11-15 18:48:54 +0000 |
1014 | +++ src/store/naive/simple_index_general.h 2011-11-19 17:32:30 +0000 |
1015 | @@ -174,6 +174,8 @@ |
1016 | |
1017 | bool insert(store::Item_t& key, store::Item_t& node); |
1018 | |
1019 | + bool insert(store::IndexKey*& key, store::Item_t& value); |
1020 | + |
1021 | virtual bool remove(const store::Item_t& key, store::Item_t& item, bool all) = 0; |
1022 | }; |
1023 | |
1024 | |
1025 | === modified file 'src/store/naive/simple_store.cpp' |
1026 | --- src/store/naive/simple_store.cpp 2011-11-02 17:19:09 +0000 |
1027 | +++ src/store/naive/simple_store.cpp 2011-11-19 17:32:30 +0000 |
1028 | @@ -555,6 +555,9 @@ |
1029 | store::Iterator* aSourceIter, |
1030 | ulong aNumColumns) |
1031 | { |
1032 | + if (!aSourceIter) |
1033 | + return; |
1034 | + |
1035 | store::Item_t domainItem; |
1036 | store::IndexKey* key = NULL; |
1037 | |
1038 | |
1039 | === added file 'test/rbkt/ExpCompilerResults/IterPlan/zorba/udf/udf-fib-rec.iter' |
1040 | --- test/rbkt/ExpCompilerResults/IterPlan/zorba/udf/udf-fib-rec.iter 1970-01-01 00:00:00 +0000 |
1041 | +++ test/rbkt/ExpCompilerResults/IterPlan/zorba/udf/udf-fib-rec.iter 2011-11-19 17:32:30 +0000 |
1042 | @@ -0,0 +1,42 @@ |
1043 | +Iterator tree for main query: |
1044 | +<UDFunctionCallIterator cached="true"> |
1045 | + <SingletonIterator value="xs:integer(100)"/> |
1046 | +</UDFunctionCallIterator> |
1047 | + |
1048 | +Iterator tree for local:fib: |
1049 | +<flwor::FLWORIterator> |
1050 | + <ForVariable name="n"> |
1051 | + <LetVarIterator varname="n"/> |
1052 | + </ForVariable> |
1053 | + <ReturnClause> |
1054 | + <IfThenElseIterator> |
1055 | + <TypedValueCompareIterator_INTEGER> |
1056 | + <ForVarIterator varname="n"/> |
1057 | + <SingletonIterator value="xs:integer(0)"/> |
1058 | + </TypedValueCompareIterator_INTEGER> |
1059 | + <SingletonIterator value="xs:integer(0)"/> |
1060 | + <IfThenElseIterator> |
1061 | + <TypedValueCompareIterator_INTEGER> |
1062 | + <ForVarIterator varname="n"/> |
1063 | + <SingletonIterator value="xs:integer(1)"/> |
1064 | + </TypedValueCompareIterator_INTEGER> |
1065 | + <SingletonIterator value="xs:integer(1)"/> |
1066 | + <SpecificNumArithIterator_AddOperation_INTEGER> |
1067 | + <UDFunctionCallIterator cached="true"> |
1068 | + <SpecificNumArithIterator_SubtractOperation_INTEGER> |
1069 | + <ForVarIterator varname="n"/> |
1070 | + <SingletonIterator value="xs:integer(1)"/> |
1071 | + </SpecificNumArithIterator_SubtractOperation_INTEGER> |
1072 | + </UDFunctionCallIterator> |
1073 | + <UDFunctionCallIterator cached="true"> |
1074 | + <SpecificNumArithIterator_SubtractOperation_INTEGER> |
1075 | + <ForVarIterator varname="n"/> |
1076 | + <SingletonIterator value="xs:integer(2)"/> |
1077 | + </SpecificNumArithIterator_SubtractOperation_INTEGER> |
1078 | + </UDFunctionCallIterator> |
1079 | + </SpecificNumArithIterator_AddOperation_INTEGER> |
1080 | + </IfThenElseIterator> |
1081 | + </IfThenElseIterator> |
1082 | + </ReturnClause> |
1083 | +</flwor::FLWORIterator> |
1084 | + |
1085 | |
1086 | === added file 'test/rbkt/ExpQueryResults/zorba/udf/udf-fib-rec.xml.res' |
1087 | --- test/rbkt/ExpQueryResults/zorba/udf/udf-fib-rec.xml.res 1970-01-01 00:00:00 +0000 |
1088 | +++ test/rbkt/ExpQueryResults/zorba/udf/udf-fib-rec.xml.res 2011-11-19 17:32:30 +0000 |
1089 | @@ -0,0 +1,1 @@ |
1090 | +3736710778780434371 |
1091 | |
1092 | === added file 'test/rbkt/Queries/zorba/udf/udf-fib-rec.xq' |
1093 | --- test/rbkt/Queries/zorba/udf/udf-fib-rec.xq 1970-01-01 00:00:00 +0000 |
1094 | +++ test/rbkt/Queries/zorba/udf/udf-fib-rec.xq 2011-11-19 17:32:30 +0000 |
1095 | @@ -0,0 +1,8 @@ |
1096 | +declare function local:fib($n as xs:integer) as xs:integer |
1097 | +{ |
1098 | + if ($n eq 0) then 0 |
1099 | + else if ($n eq 1) then 1 |
1100 | + else local:fib($n - 1) + local:fib($n - 2) |
1101 | +}; |
1102 | + |
1103 | +local:fib(100) |
Validation queue starting for merge proposal. zorbatest. lambda. nu:8080/ remotequeue/ caching- 2011-11- 04T17-29- 08.827Z/ log.html
Log at: http://