Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,27 +109,37 @@ default StringBuilder buildPercentileFunction(String functionName, double percen
* @param supportsNullsHandling whether the engine accepts {@code IGNORE NULLS}/
* {@code RESPECT NULLS}
*/
default StringBuilder buildNthValueFunction(String functionName, CharSequence operand, boolean ignoreNulls,
Integer n, List<OrderedColumn> columns, boolean supportsNullsHandling) {
/**
* The n-th value of the rows of the group, in the order of the columns, as an ordered array aggregate:
* {@code <arrayExtractOpen>ARRAY_AGG(operand ORDER BY ...) FILTER (WHERE operand IS NOT NULL)<arrayExtractClose>}.
* An aggregate, not the window function {@code NTH_VALUE ... OVER (ORDER BY ...)}: a window in a grouped
* query runs over the groups, so a cell showed the values of other members' groups (V-82). n counts from 1; a
* group with fewer values gives NULL.
*
* @param arrayAgg the dialect's ordered array aggregate, {@code ARRAY_AGG} or {@code list}
* @param open what stands before the array, {@code "("} or {@code "list_extract("}
* @param close what follows it and picks the element: {@code ")[" + n + "]"} or {@code ", " + n + ")"}
*/
default StringBuilder buildNthValueOfArray(String arrayAgg, CharSequence operand, boolean ignoreNulls,
List<OrderedColumn> columns, String open, String close) {
StringBuilder buf = new StringBuilder(64);
buf.append(functionName);
buf.append(OPEN_PAREN);
buf.append(operand);
buf.append(COMMA);
buf.append(n == null || n < 1 ? 1 : n);
buf.append(CLOSE_PAREN);
if (supportsNullsHandling) {
buf.append(ignoreNulls ? IGNORE_NULLS : RESPECT_NULLS);
}
buf.append(OVER);
buf.append(open).append(arrayAgg).append('(').append(operand);
if (columns != null && !columns.isEmpty()) {
buf.append(ORDER_BY);
buf.append(buildOrderedColumnsClause(columns));
buf.append(" ORDER BY ").append(buildOrderedColumnsClause(columns));
}
buf.append(CLOSE_PAREN);
buf.append(')');
if (ignoreNulls) {
buf.append(" FILTER (WHERE ").append(operand).append(" IS NOT NULL)");
}
buf.append(close);
return buf;
}

/** n as the element to pick: at least 1. */
static int nthIndex(Integer n) {
return n == null || n < 1 ? 1 : n;
}

default CharSequence buildOrderedColumnsClause(List<OrderedColumn> columns) {
StringBuilder buf = new StringBuilder(64);
if (columns == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,16 +233,19 @@ public java.util.Optional<String> generateListAgg(CharSequence operand, boolean
return java.util.Optional.of((buf).toString());
}

/**
* No ordered array aggregate to pick the n-th value from; the window function NTH_VALUE runs over the groups of
* a grouped query, not over the rows of one group, so it is no answer either (V-82). The measure is refused.
*/
@Override
public java.util.Optional<String> generateNthValueAgg(CharSequence operand, boolean ignoreNulls, Integer n,
List<OrderedColumn> columns) {
return java.util.Optional
.of((buildNthValueFunction("nth_value", operand, ignoreNulls, n, columns, false)).toString());
return java.util.Optional.empty();
}

@Override
public boolean supportsNthValue() {
return true;
return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class WindowFunctionTests {

@Test
void testSupportsNthValue() {
assertTrue(dialect.supportsNthValue());
assertFalse(dialect.supportsNthValue()); // V-82: no ordered array aggregate, the window form ran over the groups
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.eclipse.daanse.sql.dialect.db.duckdb;

import org.eclipse.daanse.sql.dialect.api.generator.AggregationGenerator;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -383,11 +384,12 @@ public StringBuilder buildPercentileFunction(String functionName, double percent
return buf;
}

/** The n-th value of the group's rows in their order: an ordered list, its n-th element (V-82). */
@Override
public java.util.Optional<String> generateNthValueAgg(CharSequence operand, boolean ignoreNulls, Integer n,
List<OrderedColumn> columns) {
return java.util.Optional
.of((buildNthValueFunction("NTH_VALUE", operand, ignoreNulls, n, columns, false)).toString());
return java.util.Optional.of(buildNthValueOfArray("list", operand, ignoreNulls, columns, "list_extract(",
", " + AggregationGenerator.nthIndex(n) + ")").toString());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2026 Contributors to the Eclipse Foundation.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* SmartCity Jena - initial
*/
package org.eclipse.daanse.sql.dialect.db.duckdb;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.List;

import org.junit.jupiter.api.Test;

/**
* The n-th value is an aggregate over the rows of the group -- an ordered list and its n-th element -- not the
* window NTH_VALUE ... OVER, which in a grouped query runs over the groups (V-82).
*/
class DuckDbNthValueTest {

@Test
void theNthValueIsTheNthElementOfTheGroupsList() {
assertEquals("list_extract(list(\"VALUE\") FILTER (WHERE \"VALUE\" IS NOT NULL), 2)",
new DuckDbDialect().generateNthValueAgg("\"VALUE\"", true, 2, List.of()).orElseThrow());
assertEquals("list_extract(list(\"VALUE\"), 1)",
new DuckDbDialect().generateNthValueAgg("\"VALUE\"", false, 0, List.of()).orElseThrow());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package org.eclipse.daanse.sql.dialect.db.h2;

import org.eclipse.daanse.sql.dialect.api.generator.AggregationGenerator;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -187,11 +188,12 @@ public java.util.Optional<String> generateListAgg(CharSequence operand, boolean
return java.util.Optional.of((buf).toString());
}

/** The n-th value of the group's rows in their order: an ordered array, its n-th element (V-82). */
@Override
public java.util.Optional<String> generateNthValueAgg(CharSequence operand, boolean ignoreNulls, Integer n,
List<OrderedColumn> columns) {
return java.util.Optional
.of((buildNthValueFunction("NTH_VALUE", operand, ignoreNulls, n, columns, true)).toString());
return java.util.Optional.of(buildNthValueOfArray("ARRAY_AGG", operand, ignoreNulls, columns, "(",
")[" + AggregationGenerator.nthIndex(n) + "]").toString());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,21 +469,24 @@ public java.util.Optional<String> generateListAgg(CharSequence operand, boolean
return java.util.Optional.of((buf).toString());
}

/**
* No ordered array aggregate to pick the n-th value from; the window function NTH_VALUE runs over the groups of
* a grouped query, not over the rows of one group, so it is no answer either (V-82). The measure is refused.
*/
@Override
public java.util.Optional<String> generateNthValueAgg(CharSequence operand, boolean ignoreNulls, Integer n,
List<OrderedColumn> columns) {
return java.util.Optional
.of((buildNthValueFunction("NTH_VALUE", operand, ignoreNulls, n, columns, true)).toString());
return java.util.Optional.empty();
}

@Override
public boolean supportsNthValue() {
return true;
return false;
}

@Override
public boolean supportsNthValueIgnoreNulls() {
return true;
return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -552,16 +552,19 @@ public java.util.Optional<String> generateListAgg(CharSequence operand, boolean
return java.util.Optional.of((buf).toString());
}

/**
* No ordered array aggregate to pick the n-th value from; the window function NTH_VALUE runs over the groups of
* a grouped query, not over the rows of one group, so it is no answer either (V-82). The measure is refused.
*/
@Override
public java.util.Optional<String> generateNthValueAgg(CharSequence operand, boolean ignoreNulls, Integer n,
List<OrderedColumn> columns) {
return java.util.Optional
.of((buildNthValueFunction("NTH_VALUE", operand, ignoreNulls, n, columns, false)).toString());
return java.util.Optional.empty();
}

@Override
public boolean supportsNthValue() {
return true;
return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -528,21 +528,24 @@ public java.util.Optional<String> generateListAgg(CharSequence operand, boolean
return java.util.Optional.of((buf).toString());
}

/**
* No ordered array aggregate to pick the n-th value from; the window function NTH_VALUE runs over the groups of
* a grouped query, not over the rows of one group, so it is no answer either (V-82). The measure is refused.
*/
@Override
public java.util.Optional<String> generateNthValueAgg(CharSequence operand, boolean ignoreNulls, Integer n,
List<OrderedColumn> columns) {
return java.util.Optional
.of((buildNthValueFunction("NTH_VALUE", operand, ignoreNulls, n, columns, true)).toString());
return java.util.Optional.empty();
}

@Override
public boolean supportsNthValue() {
return true;
return false;
}

@Override
public boolean supportsNthValueIgnoreNulls() {
return true;
return false;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

package org.eclipse.daanse.sql.dialect.db.postgresql;

import org.eclipse.daanse.sql.dialect.api.generator.AggregationGenerator;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
Expand Down Expand Up @@ -428,11 +429,12 @@ public java.util.Optional<String> generatePercentileCont(double percentile, bool
.of((buildPercentileFunction("PERCENTILE_CONT", percentile, desc, tableName, columnName)).toString());
}

/** The n-th value of the group's rows in their order: an ordered array, its n-th element (V-82). */
@Override
public java.util.Optional<String> generateNthValueAgg(CharSequence operand, boolean ignoreNulls, Integer n,
List<OrderedColumn> columns) {
return java.util.Optional
.of((buildNthValueFunction("NTH_VALUE", operand, ignoreNulls, n, columns, false)).toString());
return java.util.Optional.of(buildNthValueOfArray("ARRAY_AGG", operand, ignoreNulls, columns, "(",
")[" + AggregationGenerator.nthIndex(n) + "]").toString());
}

@Override
Expand Down
Loading