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

Add flags to FIRST / LAST / NTH value functions

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