The execution of a
function may involve costly processing. In general, functions that operate on a collection of objects do not need to be executed multiple times. JoSQL is not aware that functions shouldn't be executed multiple times (unlike most RDBMSs). It is therefore desirable to store the result of the processing so that on subsequent executions of the function do not incur the potentially costly processing.
JoSQL provides this ability through the use of
save values. A save value is just an "identifier", usually a
java.lang.String
(although any object can be used), that acts as a key for a value. The value can be any object.
Save values are stored in the
Query
object and are available to the developer after the query has completed. This can be done by using:
Query.getSaveValue(Object)
or
Query.getSaveValues()
.
Save values are assigned either by a function or in the
EXECUTE ON clause. If you are developing your own functions and wish to use save values to store some kind of "state" then see the
Functions section.
One point to note is that one a single copy of the save value is stored, however it can be referenced at different locations in the SQL statement, for example:
SELECT @avgLength
FROM java.io.File
WHERE length >= @avgLength
EXECUTE ON ALL avg (:_allobjs, length) avgLength
EXECUTE ON RESULTS avg (:_allobjs, length) avgLength
The 2 EXECUTE ON clauses will cause the
avg function to be called twice. First on ALL the objects passed into the
Query.execute(List)
method and then again on all the objects that match the WHERE clause. This will generally produce a different result, however the same save value id:
avgLength is used for both. The save value that will be available after the call to:
Query.execute(List)
has completed will be the result of calling
avg on the results of the WHERE clause. However, it is valid for the WHERE clause to reference the save value since it would have been initialised via the EXECUTE ON ALL clause. If you require the value of both executions to be saved then give them different aliases in the EXECUTE ON clauses (see:
Execute On Clause).
If the save value
key is a String then the case is ignored, thus the following query is valid:
SELECT *
FROM java.io.File
WHERE length >= @avgLength
EXECUTE ON ALL avg (:_allobjs, length) avglength
There are 2 ways to access the save values in the SQL statement itself.
- @ - use this special character to prefix the save value id. Of course in this case the save value id must be a string literal. Examples are shown in the previous section.
- Using the
org.josql.functions.MiscellaenousFunctions.saveValue(Object)
(or one of it's variants) to access the value. For example:
SELECT saveValue (:_currobj)
FROM java.io.File
EXECUTE ON ALL cache (:_allobjs, length)
In this case the EXECUTE ON ALL clause causes the length
value of each java.io.File
object to be cached against the object (a very contrived example!). Retrieval is then performed by using the saveValue(Object)
function with the current object.
In 90% of cases access to save values will be via string literals.
Save Values can be used in the same places as normal accessors and bind variables.
Save Values can also have "accessor"s, just like bind variables, see
Bind Variable Accessors.
For example:
SELECT @max.length
FROM java.io.File
WHERE length = maxObject (:_allobjs, length, "max")
In this case a side-effect of calling:
maxObject(:_allobjs, length, "max")
is that the object (
java.io.File
) that has the maximum length is saved in the Query object against the key: "max". When the SELECT list is executed the "length" method is accessed for that File object.
Note: JoSQL can rarely (if ever) determine the class of the Save Value when the query is inited (see
The Query), because of this the class of the object is determined when the statement is executed and will have a small performance impact, basically initialisation of the relevant Getter is deferred to execution time. In general, this is not noticeable since it is only performed once!