提交 9941a0d6 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add flags to FIRST / LAST / NTH value functions

上级 35b50ffc
......@@ -3283,10 +3283,38 @@ public class Parser {
}
read(CLOSE_PAREN);
WindowFunction function = new WindowFunction(type, currentSelect, args);
if (type == WindowFunctionType.NTH_VALUE) {
readFromFirstOrLast(function);
}
switch (type) {
case FIRST_VALUE:
case LAST_VALUE:
case NTH_VALUE:
readRespectOrIgnoreNulls(function);
//$FALL-THROUGH$
default:
// Avoid warning
}
readFilterAndOver(function);
return function;
}
private void readFromFirstOrLast(WindowFunction function) {
if (readIf(FROM) && !readIf("FIRST")) {
read("LAST");
function.setFromLast(true);
}
}
private void readRespectOrIgnoreNulls(WindowFunction function) {
if (readIf("RESPECT")) {
read("NULLS");
} else if (readIf("IGNORE")) {
read("NULLS");
function.setIgnoreNulls(true);
}
}
private Expression readFunctionWithoutParameters(String name) {
if (database.isAllowBuiltinAliasOverride()) {
FunctionAlias functionAlias = database.getSchema(session.getCurrentSchemaName()).findFunction(name);
......
......@@ -107,6 +107,10 @@ public class WindowFunction extends AbstractAggregate {
private final Expression[] args;
private boolean fromLast;
private boolean ignoreNulls;
/**
* Returns number of arguments for the specified type.
*
......@@ -126,6 +130,40 @@ public class WindowFunction extends AbstractAggregate {
}
}
private static Value getNthValue(ArrayList<Value[]> ordered, int currentRowNumber, int number, boolean fromLast,
boolean ignoreNulls) {
return ignoreNulls ? getNthValueIgnoreNulls(ordered, currentRowNumber, number, fromLast)
: ordered.get(fromLast ? currentRowNumber - number : number)[0];
}
private static Value getNthValueIgnoreNulls(ArrayList<Value[]> ordered, int currentRowNumber, int number,
boolean fromLast) {
Value v = ValueNull.INSTANCE;
int cnt = 0;
if (fromLast) {
for (int i = currentRowNumber; i >= 0; i--) {
Value t = ordered.get(i)[0];
if (t != ValueNull.INSTANCE) {
if (cnt++ == number) {
v = t;
break;
}
}
}
} else {
for (int i = 0; i <= currentRowNumber; i++) {
Value t = ordered.get(i)[0];
if (t != ValueNull.INSTANCE) {
if (cnt++ == number) {
v = t;
break;
}
}
}
}
return v;
}
/**
* Creates new instance of a window function.
*
......@@ -142,6 +180,26 @@ public class WindowFunction extends AbstractAggregate {
this.args = args;
}
/**
* Sets FROM FIRST or FROM LAST clause value.
*
* @param fromLast
* whether FROM LAST clause was specified.
*/
public void setFromLast(boolean fromLast) {
this.fromLast = fromLast;
}
/**
* Sets RESPECT NULLS or IGNORE NULLS clause value.
*
* @param ignoreNulls
* whether IGNORE NULLS clause was specified
*/
public void setIgnoreNulls(boolean ignoreNulls) {
this.ignoreNulls = ignoreNulls;
}
@Override
public boolean isAggregate() {
return false;
......@@ -232,10 +290,10 @@ public class WindowFunction extends AbstractAggregate {
break;
}
case FIRST_VALUE:
v = ordered.get(0)[0];
v = getNthValue(ordered, i, 0, false, ignoreNulls);
break;
case LAST_VALUE:
v = row[0];
v = getNthValue(ordered, i, 0, true, ignoreNulls);
break;
case NTH_VALUE: {
int n = row[1].getInt();
......@@ -243,10 +301,10 @@ public class WindowFunction extends AbstractAggregate {
throw DbException.getInvalidValueException("nth row", n);
}
n--;
if (n < 0 || n > i) {
if (n > i) {
v = ValueNull.INSTANCE;
} else {
v = ordered.get(n)[0];
v = getNthValue(ordered, i, n, fromLast, ignoreNulls);
}
break;
}
......@@ -423,6 +481,12 @@ public class WindowFunction extends AbstractAggregate {
builder.append(args[i].getSQL());
}
builder.append(')');
if (fromLast && type == WindowFunctionType.NTH_VALUE) {
builder.append(" FROM LAST");
}
if (ignoreNulls && (type == WindowFunctionType.FIRST_VALUE || type == WindowFunctionType.LAST_VALUE)) {
builder.append(" IGNORE NULLS");
}
return appendTailConditions(builder).toString();
}
......
......@@ -24,16 +24,57 @@ INSERT INTO TEST VALUES
SELECT *,
FIRST_VALUE(VALUE) OVER (ORDER BY ID) FIRST,
FIRST_VALUE(VALUE) RESPECT NULLS OVER (ORDER BY ID) FIRST_N,
FIRST_VALUE(VALUE) IGNORE NULLS OVER (ORDER BY ID) FIRST_NN,
LAST_VALUE(VALUE) OVER (ORDER BY ID) LAST,
NTH_VALUE(VALUE, 2) OVER (ORDER BY ID) NTH
FROM TEST FETCH FIRST 4 ROWS ONLY;
> ID CATEGORY VALUE FIRST LAST NTH
> -- -------- ----- ----- ---- ----
> 1 1 null null null null
> 2 1 12 null 12 12
> 3 1 null null null 12
> 4 1 13 null 13 12
> rows (ordered): 4
LAST_VALUE(VALUE) RESPECT NULLS OVER (ORDER BY ID) LAST_N,
LAST_VALUE(VALUE) IGNORE NULLS OVER (ORDER BY ID) LAST_NN
FROM TEST FETCH FIRST 6 ROWS ONLY;
> ID CATEGORY VALUE FIRST FIRST_N FIRST_NN LAST LAST_N LAST_NN
> -- -------- ----- ----- ------- -------- ---- ------ -------
> 1 1 null null null null null null null
> 2 1 12 null null 12 12 12 12
> 3 1 null null null 12 null null 12
> 4 1 13 null null 12 13 13 13
> 5 1 null null null 12 null null 13
> 6 1 13 null null 12 13 13 13
> rows (ordered): 6
SELECT *,
FIRST_VALUE(VALUE) OVER (ORDER BY ID) FIRST,
FIRST_VALUE(VALUE) RESPECT NULLS OVER (ORDER BY ID) FIRST_N,
FIRST_VALUE(VALUE) IGNORE NULLS OVER (ORDER BY ID) FIRST_NN,
LAST_VALUE(VALUE) OVER (ORDER BY ID) LAST,
LAST_VALUE(VALUE) RESPECT NULLS OVER (ORDER BY ID) LAST_N,
LAST_VALUE(VALUE) IGNORE NULLS OVER (ORDER BY ID) LAST_NN
FROM TEST WHERE ID > 1 FETCH FIRST 3 ROWS ONLY;
> ID CATEGORY VALUE FIRST FIRST_N FIRST_NN LAST LAST_N LAST_NN
> -- -------- ----- ----- ------- -------- ---- ------ -------
> 2 1 12 12 12 12 12 12 12
> 3 1 null 12 12 12 null null 12
> 4 1 13 12 12 12 13 13 13
> rows (ordered): 3
SELECT *,
NTH_VALUE(VALUE, 2) OVER (ORDER BY ID) NTH,
NTH_VALUE(VALUE, 2) FROM FIRST OVER (ORDER BY ID) NTH_FF,
NTH_VALUE(VALUE, 2) FROM LAST OVER (ORDER BY ID) NTH_FL,
NTH_VALUE(VALUE, 2) RESPECT NULLS OVER (ORDER BY ID) NTH_N,
NTH_VALUE(VALUE, 2) FROM FIRST RESPECT NULLS OVER (ORDER BY ID) NTH_FF_N,
NTH_VALUE(VALUE, 2) FROM LAST RESPECT NULLS OVER (ORDER BY ID) NTH_FL_N,
NTH_VALUE(VALUE, 2) IGNORE NULLS OVER (ORDER BY ID) NTH_NN,
NTH_VALUE(VALUE, 2) FROM FIRST IGNORE NULLS OVER (ORDER BY ID) NTH_FF_NN,
NTH_VALUE(VALUE, 2) FROM LAST IGNORE NULLS OVER (ORDER BY ID) NTH_FL_NN
FROM TEST FETCH FIRST 6 ROWS ONLY;
> ID CATEGORY VALUE NTH NTH_FF NTH_FL NTH_N NTH_FF_N NTH_FL_N NTH_NN NTH_FF_NN NTH_FL_NN
> -- -------- ----- ---- ------ ------ ----- -------- -------- ------ --------- ---------
> 1 1 null null null null null null null null null null
> 2 1 12 12 12 null 12 12 null null null null
> 3 1 null 12 12 12 12 12 12 null null null
> 4 1 13 12 12 null 12 12 null 13 13 12
> 5 1 null 12 12 13 12 12 13 13 13 12
> 6 1 13 12 12 null 12 12 null 13 13 13
> rows (ordered): 6
SELECT NTH_VALUE(VALUE, 0) OVER (ORDER BY ID) FROM TEST;
> exception INVALID_VALUE_2
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论