S
- The type of the window functions state object.O
- The type of the window functions result.public interface UserDefinedWindowFunctionAdapter<S extends Serializable,O>
Implementation of a user-defined window function involves the following steps:
ROW_NUMBER
window function a simple rowId
field is continuously incremented
for each record), and defining how to derive the final result value for the current record.Type.INTEGER
to Type.LONG
or from
Type.FLOAT
to Type.DOUBLE
may be implicitly applied by the parser and
translator when looking up a matching window function adapter. Hence a function with the signature
(Type.DOUBLE, Type.DOUBLE) -> Type.DOUBLE
also matches to a call with two Type.INTEGER
arguments or a call with one Type.INTEGER
and one Type.DOUBLE
argument. However,
if for instance any of the arguments is of type Type.BIGDECIMAL
or Type.STRING
,
the signature will not match and the adapter does not qualify for the window function call.
If the window function shall be overloaded with multiple distinct signatures a
UserDefinedWindowFunctionAdapterFactory
needs to be implemented which itself instantiates
the correct adapter for a set of input parameters if possible.
RANK
function needs its input to be ordered on a certain criteria
and thus requires the window specification to contain an ORDER BY ...
clause. Any such criteria
should be checked in the method checkWindowSpecification(boolean, boolean, WindowFrameSpecification)
and if a criteria is not met by the window specification, a corresponding IncompatibleWindowSpecificationException
should
be thrown.
createInitialState()
serves as a factory to create the very first state object for a partition. A window function
adapter itself may not maintain any internal state other than that maintained in its state-object.
While the state object is exclusively created for each partition the window function itself may
be shared among several queries.
From each new record, the query engine retrieves this window functions argument columns and wraps
them into a UserDefinedWindowFunctionAdapter.PartitionEntry
object. This currentEntry
is passed into the method
call(Serializable, PartitionEntry, Partition, int, WindowFrame, WindowFrame)
along with the state object maintained for the partition, a special view on the records in the partition,
the current index within the partition and two WindowFrame
objects, which provide the
absolute boundaries of the current and the previous window within the partition. The Partition
view
restricts access to the underlying record set so that only the records contained in the current window(s) may
be considered. Also, of those records only the derived argument values can be accessed through the UserDefinedWindowFunctionAdapter.PartitionEntry
abstraction.
The method call()
returns a pair of the new and updated state as well as the window function result value which is
appended to the current record afterwards.
getReturnType()
and getParameterTypes()
may not throw any exceptions at all,
otherwise parsing and translating the query string into a runnable query will already fail. checkWindowSpecification()
should only throw exceptions of type IncompatibleWindowSpecificationException
.
Exceptions thrown in call()
are caught and logged during query runtime but do not affect the
overall processing of the query. Instead, if call()
fails with an exception, its result will be null
.
checkWindowSpecification()
method, the adapter verifies, that the given window specification
that the function is called with includes at least one order criteria and that the window frame includes at least
any record prior to the current one (by definition of the function in the SQL Standard).
public class RankWindowFunction implements UserDefinedWindowFunctionAdapter<long[], Long>
{@Override
public Type getReturnType() { return Type.LONG; }@Override
public Type[] getParameterTypes() { return new Type[0]; }@Override
public long[] createInitialState() { return new long[] {1, 0}; // current rank, tie-score }@Override
public WindowFunctionResultcall(long[] state, PartitionEntry currentEntry, Partition partition, int currentIndex, WindowFrame currentWindowFrame, WindowFrame prevWindowFrame) { if (currentIndex == 0) return Adapters.createWindowFunctionResult(state, state[0]); if (currentEntry.compareTo(partition.get(currentIndex - 1)) == 0) state[1]++; // increment tie score else { state[0] += 1 + state[1]; // increment rank state[1] = 0; } return Adapters.createWindowFunctionResult(state, state[0]); } @Override
public void checkWindowSpecification(boolean isPartitioned, boolean isOrdered, WindowFrameSpecification windowFrameSpecification) throws IncompatibleWindowSpecificationException { if (!isOrdered) throw new IncompatibleWindowSpecificationException("The rank window function requires at least one order specification to be given in the window clause."); if (!windowFrameSpecification.isUnboundedPrecedingToAtLeastCurrentRow()) throw new IncompatibleWindowSpecificationException("The rank window function does not accept a bounded frame given in the window specification."); } }
Modifier and Type | Interface and Description |
---|---|
static interface |
UserDefinedWindowFunctionAdapter.Partition
A
Partition provides a view on a set of records that a window
function is applied on. |
static interface |
UserDefinedWindowFunctionAdapter.PartitionEntry
A
PartitionEntry provides a view on the argument values of a
window function call. |
Modifier and Type | Method and Description |
---|---|
WindowFunctionResult<S,O> |
call(S state,
UserDefinedWindowFunctionAdapter.PartitionEntry currentEntry,
UserDefinedWindowFunctionAdapter.Partition partition,
int currentIndex,
WindowFrame currentWindowSpec,
WindowFrame previousWindowSpec)
Evaluates the window function for the current record.
|
void |
checkWindowSpecification(boolean isPartitioned,
boolean isOrdered,
WindowFrameSpecification windowFrameSpecification)
For a particular window function call, this method checks whether or not this window function adapter may be called with the
window specification as specified in the window functions
OVER() clause. |
S |
createInitialState()
Creates an empty initial state used for the window function computation.
|
JavaTypes.Type[] |
getParameterTypes()
Returns the parameter types of the user-defined function.
|
JavaTypes.Type |
getReturnType()
Return the return type of the user-defined function.
|
JavaTypes.Type getReturnType()
JavaTypes.Type[] getParameterTypes()
void checkWindowSpecification(boolean isPartitioned, boolean isOrdered, WindowFrameSpecification windowFrameSpecification) throws IncompatibleWindowSpecificationException
OVER()
clause. For example, a common criteria to check here
could be whether or not the input record set/partition is ordered. If the window function requires an ordered input and the
input is not ordered this method should then throw an IncompatibleWindowSpecificationException
.
isPartitioned
- indicates whether or not the input record set is divided into partitions as defined in the window functions OVER(PARTITION BY key...)
clauseisOrdered
- indicates whether or not the input record set is ordered according to the window functions OVER([...] ORDER BY key...)
clausewindowFrameSpecification
- describes the window frame as specified in the window functions OVER([...] (ROWS|RANGE)...)
clauseIncompatibleWindowSpecificationException
- if the window specification does not meet the requirements of this window function adapterS createInitialState()
call()
.WindowFunctionResult<S,O> call(S state, UserDefinedWindowFunctionAdapter.PartitionEntry currentEntry, UserDefinedWindowFunctionAdapter.Partition partition, int currentIndex, WindowFrame currentWindowSpec, WindowFrame previousWindowSpec)
PartitionEntry
from the Partition
which either lies within the current window frame or which lied in the window frame of the previous
function call. The Partition
may restrict access to any other PartitionEntry
.
Note:The WindowFrame
objects as well as the currentIndex
represent absolute indexes into the Partition
, i.e. the following
equations hold for each call: 0 <= windowSpec.getStart() <= windowSpec.getEnd() < partition.size()
and also currentEntry == partition.get(currentIndex)
.
state
- the state of the window function prior to this callcurrentEntry
- the PartitionEntry
wrapping around the argument columns taken from the current recordpartition
- the whole input partition providing a viewcurrentIndex
- the absolute index of the current entry within the partitioncurrentWindowSpec
- the absolute indexes of the current window framepreviousWindowSpec
- the absolute indexes of the previously processed window frame. This may be taken into account when computing the delta of what has changed when sliding
from one window to the next one.