orderBy(Collection extends OrderField>> fields);
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java
index 768ff3bcf3..c99b656685 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DSL.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java
@@ -304,6 +304,7 @@ import org.jooq.Name;
import org.jooq.Name.Quoted;
import org.jooq.Null;
import org.jooq.Operator;
+import org.jooq.OptionallyOrderedAggregateFunction;
import org.jooq.OrderField;
import org.jooq.OrderedAggregateFunction;
import org.jooq.OrderedAggregateFunctionOfDeferredType;
@@ -24617,6 +24618,20 @@ public class DSL {
return new Max<>(field, true);
}
+ /**
+ * The MAX_BY function.
+ *
+ * Evaluate value at the row having the maximum value for by.
+ *
+ * @param value The returned value.
+ * @param by The expression to use to evaluate the maximum.
+ */
+ @NotNull
+ @Support({ DUCKDB, TRINO })
+ public static OptionallyOrderedAggregateFunction maxBy(Field value, Field> by) {
+ return new MaxBy<>(value, by);
+ }
+
/**
* The MEDIAN function.
*/
@@ -24644,6 +24659,20 @@ public class DSL {
return new Min<>(field, true);
}
+ /**
+ * The MIN_BY function.
+ *
+ * Evaluate value at the row having the minimum value for by.
+ *
+ * @param value The returned value.
+ * @param by The expression to use to evaluate the minimum
+ */
+ @NotNull
+ @Support({ DUCKDB, TRINO })
+ public static OptionallyOrderedAggregateFunction minBy(Field value, Field> by) {
+ return new MinBy<>(value, by);
+ }
+
/**
* The PRODUCT function.
*
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
index 518f0609b8..ccc1ac0416 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultBinding.java
@@ -1418,6 +1418,13 @@ public class DefaultBinding implements Binding {
t = byte[][].class;
}
+ // [#16585] Another HSQLDB bug regarding LocalTime:
+ // See also: https://sourceforge.net/p/hsqldb/bugs/1702/
+ else if (t == LocalTime[].class) {
+ a = (Object[]) Convert.convertArray(a, Time[].class);
+ t = Time[].class;
+ }
+
ctx.statement().setArray(ctx.index(), new MockArray(ctx.family(), a, t));
break;
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/MaxBy.java b/jOOQ/src/main/java/org/jooq/impl/MaxBy.java
new file mode 100644
index 0000000000..31b4854638
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/MaxBy.java
@@ -0,0 +1,207 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: https://www.jooq.org/legal/licensing
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq.impl;
+
+import static org.jooq.impl.DSL.*;
+import static org.jooq.impl.Internal.*;
+import static org.jooq.impl.Keywords.*;
+import static org.jooq.impl.Names.*;
+import static org.jooq.impl.SQLDataType.*;
+import static org.jooq.impl.Tools.*;
+import static org.jooq.impl.Tools.BooleanDataKey.*;
+import static org.jooq.impl.Tools.ExtendedDataKey.*;
+import static org.jooq.impl.Tools.SimpleDataKey.*;
+import static org.jooq.SQLDialect.*;
+
+import org.jooq.*;
+import org.jooq.Function1;
+import org.jooq.Record;
+import org.jooq.conf.*;
+import org.jooq.tools.*;
+
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+
+
+/**
+ * The MAX BY statement.
+ */
+@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
+final class MaxBy
+extends
+ AbstractAggregateFunction
+implements
+ QOM.MaxBy
+{
+
+ MaxBy(
+ Field value,
+ Field> by
+ ) {
+ super(
+ false,
+ N_MAX_BY,
+ Tools.nullSafeDataType(value),
+ nullSafeNotNull(value, (DataType) OTHER),
+ nullSafeNotNull(by, OTHER)
+ );
+ }
+
+ // -------------------------------------------------------------------------
+ // XXX: QueryPart API
+ // -------------------------------------------------------------------------
+
+
+
+ @Override
+ public final void accept(Context> ctx) {
+ switch (ctx.family()) {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ default:
+ acceptFunctionName(ctx);
+ ctx.sql('(');
+ acceptArguments0(ctx);
+ acceptOrderBy(ctx);
+ ctx.sql(')');
+
+ acceptFilterClause(ctx);
+ acceptOverClause(ctx);
+ break;
+ }
+ }
+
+ @Override
+ final void acceptFunctionName(Context> ctx) {
+ switch (ctx.family()) {
+ case CLICKHOUSE:
+ ctx.visit(N_argMax);
+ break;
+
+ default:
+ super.acceptFunctionName(ctx);
+ break;
+ }
+ }
+
+
+
+ // -------------------------------------------------------------------------
+ // XXX: Query Object Model
+ // -------------------------------------------------------------------------
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final Field $value() {
+ return (Field) getArgument(0);
+ }
+
+ @Override
+ public final Field> $by() {
+ return getArgument(1);
+ }
+
+ @Override
+ public final QOM.MaxBy $value(Field newValue) {
+ return $constructor().apply(newValue, $by());
+ }
+
+ @Override
+ public final QOM.MaxBy $by(Field> newValue) {
+ return $constructor().apply($value(), newValue);
+ }
+
+ public final Function2 super Field, ? super Field>, ? extends QOM.MaxBy> $constructor() {
+ return (a1, a2) -> new MaxBy<>(a1, a2);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ // -------------------------------------------------------------------------
+ // XXX: The Object API
+ // -------------------------------------------------------------------------
+
+ @Override
+ public boolean equals(Object that) {
+ if (that instanceof QOM.MaxBy> o) {
+ return
+ StringUtils.equals($value(), o.$value()) &&
+ StringUtils.equals($by(), o.$by())
+ ;
+ }
+ else
+ return super.equals(that);
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/MinBy.java b/jOOQ/src/main/java/org/jooq/impl/MinBy.java
new file mode 100644
index 0000000000..a4b81a991e
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/MinBy.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: https://www.jooq.org/legal/licensing
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq.impl;
+
+import static org.jooq.impl.DSL.*;
+import static org.jooq.impl.Internal.*;
+import static org.jooq.impl.Keywords.*;
+import static org.jooq.impl.Names.*;
+import static org.jooq.impl.SQLDataType.*;
+import static org.jooq.impl.Tools.*;
+import static org.jooq.impl.Tools.BooleanDataKey.*;
+import static org.jooq.impl.Tools.ExtendedDataKey.*;
+import static org.jooq.impl.Tools.SimpleDataKey.*;
+import static org.jooq.SQLDialect.*;
+
+import org.jooq.*;
+import org.jooq.Function1;
+import org.jooq.Record;
+import org.jooq.conf.*;
+import org.jooq.tools.*;
+
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+
+
+/**
+ * The MIN BY statement.
+ */
+@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
+final class MinBy
+extends
+ AbstractAggregateFunction
+implements
+ QOM.MinBy
+{
+
+ MinBy(
+ Field value,
+ Field> by
+ ) {
+ super(
+ false,
+ N_MIN_BY,
+ Tools.nullSafeDataType(value),
+ nullSafeNotNull(value, (DataType) OTHER),
+ nullSafeNotNull(by, OTHER)
+ );
+ }
+
+ // -------------------------------------------------------------------------
+ // XXX: QueryPart API
+ // -------------------------------------------------------------------------
+
+
+
+ @Override
+ public final void accept(Context> ctx) {
+ switch (ctx.family()) {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ default:
+ acceptFunctionName(ctx);
+ ctx.sql('(');
+ acceptArguments0(ctx);
+ acceptOrderBy(ctx);
+ ctx.sql(')');
+
+ acceptFilterClause(ctx);
+ acceptOverClause(ctx);
+ break;
+ }
+ }
+
+ @Override
+ final void acceptFunctionName(Context> ctx) {
+ switch (ctx.family()) {
+ case CLICKHOUSE:
+ ctx.visit(N_argMin);
+ break;
+
+ default:
+ super.acceptFunctionName(ctx);
+ break;
+ }
+ }
+
+
+
+ // -------------------------------------------------------------------------
+ // XXX: Query Object Model
+ // -------------------------------------------------------------------------
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final Field $value() {
+ return (Field) getArgument(0);
+ }
+
+ @Override
+ public final Field> $by() {
+ return getArgument(1);
+ }
+
+ @Override
+ public final QOM.MinBy $value(Field newValue) {
+ return $constructor().apply(newValue, $by());
+ }
+
+ @Override
+ public final QOM.MinBy $by(Field> newValue) {
+ return $constructor().apply($value(), newValue);
+ }
+
+ public final Function2 super Field, ? super Field>, ? extends QOM.MinBy> $constructor() {
+ return (a1, a2) -> new MinBy<>(a1, a2);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ // -------------------------------------------------------------------------
+ // XXX: The Object API
+ // -------------------------------------------------------------------------
+
+ @Override
+ public boolean equals(Object that) {
+ if (that instanceof QOM.MinBy> o) {
+ return
+ StringUtils.equals($value(), o.$value()) &&
+ StringUtils.equals($by(), o.$by())
+ ;
+ }
+ else
+ return super.equals(that);
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/Names.java b/jOOQ/src/main/java/org/jooq/impl/Names.java
index dd8b5fc328..fa5cc137d3 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Names.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Names.java
@@ -69,6 +69,8 @@ final class Names {
static final Name N_ADD_YEARS = systemName("add_years");
static final Name N_ANY = systemName("any");
static final Name N_ARBITRARY = systemName("arbitrary");
+ static final Name N_argMax = systemName("argMax");
+ static final Name N_argMin = systemName("argMin");
static final Name N_ARRAY = systemName("array");
static final Name N_ARRAY_AGG = systemName("array_agg");
static final Name N_ARRAY_CONSTRUCT = systemName("array_construct");
@@ -521,9 +523,11 @@ final class Names {
static final Name N_LTRIM = systemName("ltrim");
static final Name N_MAP_KEYS = systemName("map_keys");
static final Name N_MAX = systemName("max");
+ static final Name N_MAX_BY = systemName("max_by");
static final Name N_MD5 = systemName("md5");
static final Name N_MEDIAN = systemName("median");
static final Name N_MIN = systemName("min");
+ static final Name N_MIN_BY = systemName("min_by");
static final Name N_NEWID = systemName("newid");
static final Name N_NONE_MATCH = systemName("none_match");
static final Name N_NULLIF = systemName("nullif");
diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
index 5787eff974..0bf7e9c140 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
@@ -254,6 +254,7 @@ import static org.jooq.impl.DSL.log10;
import static org.jooq.impl.DSL.lower;
import static org.jooq.impl.DSL.ltrim;
import static org.jooq.impl.DSL.max;
+import static org.jooq.impl.DSL.maxBy;
import static org.jooq.impl.DSL.maxDistinct;
import static org.jooq.impl.DSL.md5;
import static org.jooq.impl.DSL.median;
@@ -261,6 +262,7 @@ import static org.jooq.impl.DSL.microsecond;
import static org.jooq.impl.DSL.millennium;
import static org.jooq.impl.DSL.millisecond;
import static org.jooq.impl.DSL.min;
+import static org.jooq.impl.DSL.minBy;
import static org.jooq.impl.DSL.minDistinct;
import static org.jooq.impl.DSL.minute;
import static org.jooq.impl.DSL.mode;
@@ -663,6 +665,7 @@ import org.jooq.MergeMatchedWhereStep;
import org.jooq.MergeUsingStep;
import org.jooq.Meta;
import org.jooq.Name;
+import org.jooq.OptionallyOrderedAggregateFunction;
import org.jooq.Name.Quoted;
import org.jooq.OrderedAggregateFunction;
import org.jooq.OrderedAggregateFunctionOfDeferredType;
@@ -12149,6 +12152,8 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
over = filter = agg = parseBinarySetFunctionIf();
if (filter == null && !basic)
over = filter = parseOrderedSetFunctionIf();
+ if (filter == null && !basic)
+ over = filter = parseMinMaxByFunctionIf();
if (filter == null && !basic)
over = filter = parseArrayAggFunctionIf();
if (filter == null && !basic)
@@ -12536,6 +12541,31 @@ final class DefaultParseContext extends AbstractScope implements ParseContext {
return null;
}
+ private final AggregateFilterStep> parseMinMaxByFunctionIf() {
+ boolean minBy = parseFunctionNameIf("MIN_BY", "ARG_MIN", "argMin");
+ boolean maxBy = !minBy && parseFunctionNameIf("MAX_BY", "ARG_MAX", "argMax");
+
+ if (minBy || maxBy) {
+ parse('(');
+ parseSetQuantifier();
+ Field> f1 = parseField();
+ parse(',');
+ Field> f2 = parseField();
+
+ List> sort = null;
+
+ if (parseKeywordIf("ORDER BY"))
+ sort = parseList(',', c -> c.parseSortField());
+
+ parse(')');
+
+ OptionallyOrderedAggregateFunction> s1 = minBy ? minBy(f1, f2) : maxBy(f1, f2);
+ return sort == null ? s1 : s1.orderBy(sort);
+ }
+
+ return null;
+ }
+
private final AggregateFilterStep> parseArrayAggFunctionIf() {
if (parseKeywordIf("ARRAY_AGG", "groupArray")) {
parse('(');
diff --git a/jOOQ/src/main/java/org/jooq/impl/QOM.java b/jOOQ/src/main/java/org/jooq/impl/QOM.java
index 18bc896675..690bba0384 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QOM.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QOM.java
@@ -8027,6 +8027,41 @@ public final class QOM {
@NotNull Max $distinct(boolean distinct);
}
+ /**
+ * The MAX BY function.
+ *
+ * Evaluate value at the row having the maximum value for by.
+ */
+ public /*sealed*/ interface MaxBy
+ extends
+ org.jooq.OptionallyOrderedAggregateFunction
+ //permits
+ // MaxBy
+ {
+
+ /**
+ * The returned value.
+ */
+ @NotNull Field $value();
+
+ /**
+ * The expression to use to evaluate the maximum.
+ */
+ @NotNull Field> $by();
+
+ /**
+ * The returned value.
+ */
+ @CheckReturnValue
+ @NotNull MaxBy $value(Field value);
+
+ /**
+ * The expression to use to evaluate the maximum.
+ */
+ @CheckReturnValue
+ @NotNull MaxBy $by(Field> by);
+ }
+
/**
* The MEDIAN function.
*/
@@ -8058,6 +8093,41 @@ public final class QOM {
@NotNull Min $distinct(boolean distinct);
}
+ /**
+ * The MIN BY function.
+ *
+ * Evaluate value at the row having the minimum value for by.
+ */
+ public /*sealed*/ interface MinBy
+ extends
+ org.jooq.OptionallyOrderedAggregateFunction
+ //permits
+ // MinBy
+ {
+
+ /**
+ * The returned value.
+ */
+ @NotNull Field $value();
+
+ /**
+ * The expression to use to evaluate the minimum
+ */
+ @NotNull Field> $by();
+
+ /**
+ * The returned value.
+ */
+ @CheckReturnValue
+ @NotNull MinBy $value(Field value);
+
+ /**
+ * The expression to use to evaluate the minimum
+ */
+ @CheckReturnValue
+ @NotNull MinBy $by(Field> by);
+ }
+
/**
* The PRODUCT function.
*
diff --git a/pom.xml b/pom.xml
index 6a34dca9b4..99f0a7630a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,7 @@
2.7.2
- 42.7.2
+ 42.7.3
12.4.2.jre11
23.3.0.23.09