[jOOQ/jOOQ#9930] Extracted AbstractAggregateFunction
This commit is contained in:
parent
0879b28c3b
commit
c7e1389245
289
jOOQ/src/main/java/org/jooq/impl/AbstractAggregateFunction.java
Normal file
289
jOOQ/src/main/java/org/jooq/impl/AbstractAggregateFunction.java
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
import static org.jooq.impl.DSL.condition;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.Keywords.K_DISTINCT;
|
||||
import static org.jooq.impl.Keywords.K_FILTER;
|
||||
import static org.jooq.impl.Keywords.K_WHERE;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.AggregateFilterStep;
|
||||
import org.jooq.AggregateFunction;
|
||||
import org.jooq.ArrayAggOrderByStep;
|
||||
import org.jooq.Condition;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.OrderField;
|
||||
import org.jooq.OrderedAggregateFunction;
|
||||
// ...
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.SQL;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.WindowBeforeOverStep;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
abstract class AbstractAggregateFunction<T>
|
||||
extends AbstractWindowFunction<T>
|
||||
implements
|
||||
AggregateFunction<T>,
|
||||
OrderedAggregateFunction<T>,
|
||||
ArrayAggOrderByStep<T> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -8613744948308064895L;
|
||||
private static final Set<SQLDialect> SUPPORT_FILTER = SQLDialect.supportedBy(H2, HSQLDB, POSTGRES, SQLITE);
|
||||
private static final Set<SQLDialect> SUPPORT_DISTINCT_RVE = SQLDialect.supportedBy(H2, POSTGRES);
|
||||
|
||||
static final Field<Integer> ASTERISK = DSL.field("*", Integer.class);
|
||||
|
||||
// Other attributes
|
||||
final QueryPartList<Field<?>> arguments;
|
||||
final boolean distinct;
|
||||
Condition filter;
|
||||
|
||||
// Other attributes
|
||||
SortFieldList withinGroupOrderBy;
|
||||
SortFieldList keepDenseRankOrderBy;
|
||||
boolean first;
|
||||
|
||||
AbstractAggregateFunction(boolean distinct, Name name, DataType<T> type, Field<?>... arguments) {
|
||||
super(name, type);
|
||||
|
||||
this.distinct = distinct;
|
||||
this.arguments = new QueryPartList<>(arguments);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
final void acceptArguments(Context<?> ctx) {
|
||||
ctx.sql(getName());
|
||||
ctx.sql('(');
|
||||
acceptArguments0(ctx);
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
final void acceptArguments0(Context<?> ctx) {
|
||||
acceptArguments1(ctx, arguments);
|
||||
}
|
||||
|
||||
final void acceptArguments1(Context<?> ctx, QueryPartList<Field<?>> args) {
|
||||
if (distinct) {
|
||||
ctx.visit(K_DISTINCT).sql(' ');
|
||||
|
||||
// [#2883][#9109] PostgreSQL and H2 can use the DISTINCT keyword with formal row value expressions.
|
||||
if (args.size() > 1 && SUPPORT_DISTINCT_RVE.contains(ctx.family()))
|
||||
ctx.sql('(');
|
||||
}
|
||||
|
||||
if (!args.isEmpty()) {
|
||||
if (filter == null || SUPPORT_FILTER.contains(ctx.dialect())) {
|
||||
ctx.visit(args);
|
||||
}
|
||||
else {
|
||||
QueryPartList<Field<?>> expressions = new QueryPartList<>();
|
||||
|
||||
for (Field<?> argument : args)
|
||||
expressions.add(DSL.when(filter, argument == ASTERISK ? one() : argument));
|
||||
|
||||
ctx.visit(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
if (distinct)
|
||||
if (args.size() > 1 && SUPPORT_DISTINCT_RVE.contains(ctx.family()))
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
final void acceptFilterClause(Context<?> ctx) {
|
||||
if (filter != null && SUPPORT_FILTER.contains(ctx.dialect()))
|
||||
ctx.sql(' ')
|
||||
.visit(K_FILTER)
|
||||
.sql(" (")
|
||||
.visit(K_WHERE)
|
||||
.sql(' ')
|
||||
.visit(filter)
|
||||
.sql(')');
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Aggregate function API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
final QueryPartList<Field<?>> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Condition c) {
|
||||
filter = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Condition... conditions) {
|
||||
return filterWhere(Arrays.asList(conditions));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Collection<? extends Condition> conditions) {
|
||||
ConditionProviderImpl c = new ConditionProviderImpl();
|
||||
c.addConditions(conditions);
|
||||
return filterWhere(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Field<Boolean> field) {
|
||||
return filterWhere(condition(field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Boolean field) {
|
||||
return filterWhere(condition(field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(SQL sql) {
|
||||
return filterWhere(condition(sql));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(String sql) {
|
||||
return filterWhere(condition(sql));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(String sql, Object... bindings) {
|
||||
return filterWhere(condition(sql, bindings));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(String sql, QueryPart... parts) {
|
||||
return filterWhere(condition(sql, parts));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(OrderField<?>... fields) {
|
||||
return withinGroupOrderBy(Arrays.asList(fields));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(Collection<? extends OrderField<?>> fields) {
|
||||
if (withinGroupOrderBy == null)
|
||||
withinGroupOrderBy = new SortFieldList();
|
||||
|
||||
withinGroupOrderBy.addAll(Tools.sortFields(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public final AbstractAggregateFunction<T> orderBy(OrderField<?>... fields) {
|
||||
if (windowSpecification != null)
|
||||
windowSpecification.orderBy(fields);
|
||||
else
|
||||
withinGroupOrderBy(fields);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AbstractAggregateFunction<T> orderBy(Collection<? extends OrderField<?>> fields) {
|
||||
if (windowSpecification != null)
|
||||
windowSpecification.orderBy(fields);
|
||||
else
|
||||
withinGroupOrderBy(fields);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ final class CountTable extends DefaultAggregateFunction<Integer> {
|
||||
private final boolean distinct;
|
||||
|
||||
CountTable(Table<?> table, boolean distinct) {
|
||||
super("count", distinct, SQLDataType.INTEGER, DSL.field(DSL.name(table.getName())));
|
||||
super(distinct, "count", SQLDataType.INTEGER, DSL.field(DSL.name(table.getName())));
|
||||
|
||||
this.table = table;
|
||||
this.distinct = distinct;
|
||||
@ -78,7 +78,7 @@ final class CountTable extends DefaultAggregateFunction<Integer> {
|
||||
UniqueKey<?> pk = table.getPrimaryKey();
|
||||
|
||||
if (pk != null)
|
||||
ctx.visit(new DefaultAggregateFunction<>("count", distinct, SQLDataType.INTEGER, table.fields(pk.getFieldsArray())));
|
||||
ctx.visit(new DefaultAggregateFunction<>(distinct, "count", SQLDataType.INTEGER, table.fields(pk.getFieldsArray())));
|
||||
else
|
||||
super.accept(ctx);
|
||||
|
||||
|
||||
@ -18220,7 +18220,7 @@ public class DSL {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<Integer> countDistinct(Field<?> field) {
|
||||
return new DefaultAggregateFunction<>("count", true, SQLDataType.INTEGER, nullSafe(field));
|
||||
return new DefaultAggregateFunction<>(true, "count", SQLDataType.INTEGER, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18228,7 +18228,7 @@ public class DSL {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<Integer> countDistinct(SelectFieldOrAsterisk field) {
|
||||
return new DefaultAggregateFunction<>("count", true, SQLDataType.INTEGER, field("{0}", field));
|
||||
return new DefaultAggregateFunction<>(true, "count", SQLDataType.INTEGER, field("{0}", field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18255,7 +18255,7 @@ public class DSL {
|
||||
@Support({ H2, HSQLDB, MARIADB, MYSQL, POSTGRES })
|
||||
public static AggregateFunction<Integer> countDistinct(Field<?>... fields) {
|
||||
fields = nullSafe(fields);
|
||||
return fields.length == 0 ? countDistinct(asterisk()) : new DefaultAggregateFunction<>("count", true, SQLDataType.INTEGER, fields);
|
||||
return fields.length == 0 ? countDistinct(asterisk()) : new DefaultAggregateFunction<>(true, "count", SQLDataType.INTEGER, fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18323,7 +18323,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ HSQLDB, POSTGRES })
|
||||
public static <T> ArrayAggOrderByStep<T[]> arrayAggDistinct(Field<T> field) {
|
||||
return new DefaultAggregateFunction<>(Term.ARRAY_AGG, true, field.getDataType().getArrayDataType(), nullSafe(field));
|
||||
return new DefaultAggregateFunction<>(true, Term.ARRAY_AGG, field.getDataType().getArrayDataType(), nullSafe(field));
|
||||
}
|
||||
|
||||
|
||||
@ -18483,7 +18483,7 @@ public class DSL {
|
||||
*/
|
||||
@Support
|
||||
public static <T> AggregateFunction<T> maxDistinct(Field<T> field) {
|
||||
return new DefaultAggregateFunction<>("max", true, nullSafeDataType(field), nullSafe(field));
|
||||
return new DefaultAggregateFunction<>(true, "max", nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18499,7 +18499,7 @@ public class DSL {
|
||||
*/
|
||||
@Support
|
||||
public static <T> AggregateFunction<T> minDistinct(Field<T> field) {
|
||||
return new DefaultAggregateFunction<>("min", true, nullSafeDataType(field), nullSafe(field));
|
||||
return new DefaultAggregateFunction<>(true, "min", nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18515,7 +18515,7 @@ public class DSL {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<BigDecimal> sumDistinct(Field<? extends Number> field) {
|
||||
return new DefaultAggregateFunction<>("sum", true, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new DefaultAggregateFunction<>(true, "sum", SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18533,7 +18533,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, MARIADB, MYSQL, POSTGRES })
|
||||
public static AggregateFunction<BigDecimal> product(Field<? extends Number> field) {
|
||||
return new DefaultAggregateFunction<>(Term.PRODUCT, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Product(false, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18551,7 +18551,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, MARIADB, MYSQL, POSTGRES })
|
||||
public static AggregateFunction<BigDecimal> productDistinct(Field<? extends Number> field) {
|
||||
return new DefaultAggregateFunction<>(Term.PRODUCT, true, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Product(true, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18567,7 +18567,7 @@ public class DSL {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<BigDecimal> avgDistinct(Field<? extends Number> field) {
|
||||
return new DefaultAggregateFunction<>("avg", true, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new DefaultAggregateFunction<>(true, "avg", SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18583,7 +18583,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MARIADB, POSTGRES })
|
||||
public static AggregateFunction<BigDecimal> median(Field<? extends Number> field) {
|
||||
return new DefaultAggregateFunction<>(Term.MEDIAN, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Median(nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18772,7 +18772,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MARIADB, MYSQL, POSTGRES })
|
||||
public static OrderedAggregateFunction<String> listAgg(Field<?> field) {
|
||||
return new DefaultAggregateFunction<>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field));
|
||||
return new ListAgg(false, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18794,7 +18794,7 @@ public class DSL {
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MARIADB, MYSQL, POSTGRES })
|
||||
public static OrderedAggregateFunction<String> listAgg(Field<?> field, String separator) {
|
||||
return new DefaultAggregateFunction<>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field), inline(separator));
|
||||
return new ListAgg(false, nullSafe(field), inline(separator));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -40,73 +40,28 @@ package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
import static org.jooq.SQLDialect.MARIADB;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.MYSQL;
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.choose;
|
||||
import static org.jooq.impl.DSL.condition;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.mode;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.percentileCont;
|
||||
import static org.jooq.impl.DSL.when;
|
||||
import static org.jooq.impl.DSL.zero;
|
||||
import static org.jooq.impl.Keywords.F_CONCAT;
|
||||
import static org.jooq.impl.Keywords.F_SUBSTR;
|
||||
import static org.jooq.impl.Keywords.F_XMLAGG;
|
||||
import static org.jooq.impl.Keywords.F_XMLSERIALIZE;
|
||||
import static org.jooq.impl.Keywords.F_XMLTEXT;
|
||||
import static org.jooq.impl.Keywords.K_AS;
|
||||
import static org.jooq.impl.Keywords.K_DENSE_RANK;
|
||||
import static org.jooq.impl.Keywords.K_DISTINCT;
|
||||
import static org.jooq.impl.Keywords.K_FILTER;
|
||||
import static org.jooq.impl.Keywords.K_FIRST;
|
||||
import static org.jooq.impl.Keywords.K_KEEP;
|
||||
import static org.jooq.impl.Keywords.K_LAST;
|
||||
import static org.jooq.impl.Keywords.K_NULL;
|
||||
import static org.jooq.impl.Keywords.K_ORDER_BY;
|
||||
import static org.jooq.impl.Keywords.K_SEPARATOR;
|
||||
import static org.jooq.impl.Keywords.K_WHERE;
|
||||
import static org.jooq.impl.Keywords.K_WITHIN_GROUP;
|
||||
import static org.jooq.impl.SQLDataType.NUMERIC;
|
||||
import static org.jooq.impl.Term.ARRAY_AGG;
|
||||
import static org.jooq.impl.Term.LIST_AGG;
|
||||
import static org.jooq.impl.Term.MEDIAN;
|
||||
import static org.jooq.impl.Term.MODE;
|
||||
import static org.jooq.impl.Term.PRODUCT;
|
||||
import static org.jooq.impl.Tools.castIfNeeded;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.AggregateFilterStep;
|
||||
import org.jooq.AggregateFunction;
|
||||
import org.jooq.ArrayAggOrderByStep;
|
||||
import org.jooq.Condition;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.OrderField;
|
||||
import org.jooq.OrderedAggregateFunction;
|
||||
// ...
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.SQL;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.WindowBeforeOverStep;
|
||||
// ...
|
||||
|
||||
/**
|
||||
* A field that handles built-in functions, aggregate functions, and window
|
||||
@ -114,64 +69,45 @@ import org.jooq.WindowBeforeOverStep;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class DefaultAggregateFunction<T> extends AbstractWindowFunction<T> implements
|
||||
|
||||
// Cascading interface implementations for aggregate function behaviour
|
||||
OrderedAggregateFunction<T>,
|
||||
ArrayAggOrderByStep<T>,
|
||||
AggregateFunction<T> {
|
||||
class DefaultAggregateFunction<T> extends AbstractAggregateFunction<T> {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 347252741712134044L;
|
||||
private static final Set<SQLDialect> SUPPORT_ARRAY_AGG = SQLDialect.supportedBy(HSQLDB, POSTGRES);
|
||||
private static final Set<SQLDialect> SUPPORT_GROUP_CONCAT = SQLDialect.supportedBy(CUBRID, H2, HSQLDB, MARIADB, MYSQL, SQLITE);
|
||||
private static final Set<SQLDialect> SUPPORT_STRING_AGG = SQLDialect.supportedBy(POSTGRES);
|
||||
private static final Set<SQLDialect> SUPPORT_FILTER = SQLDialect.supportedBy(H2, HSQLDB, POSTGRES, SQLITE);
|
||||
private static final Set<SQLDialect> SUPPORT_DISTINCT_RVE = SQLDialect.supportedBy(H2, POSTGRES);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static final Field<Integer> ASTERISK = DSL.field("*", Integer.class);
|
||||
|
||||
// Mutually exclusive attributes: super.getName(), this.term
|
||||
private final Term term;
|
||||
|
||||
// Other attributes
|
||||
private final QueryPartList<Field<?>> arguments;
|
||||
private final boolean distinct;
|
||||
private SortFieldList withinGroupOrderBy;
|
||||
private SortFieldList keepDenseRankOrderBy;
|
||||
private Condition filter;
|
||||
private boolean first;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Constructors
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
DefaultAggregateFunction(String name, DataType<T> type, Field<?>... arguments) {
|
||||
this(name, false, type, arguments);
|
||||
this(false, name, type, arguments);
|
||||
}
|
||||
|
||||
DefaultAggregateFunction(Name name, DataType<T> type, Field<?>... arguments) {
|
||||
this(false, name, type, arguments);
|
||||
}
|
||||
|
||||
DefaultAggregateFunction(Term term, DataType<T> type, Field<?>... arguments) {
|
||||
this(term, false, type, arguments);
|
||||
this(false, term, type, arguments);
|
||||
}
|
||||
|
||||
DefaultAggregateFunction(String name, boolean distinct, DataType<T> type, Field<?>... arguments) {
|
||||
super(DSL.name(name), type);
|
||||
DefaultAggregateFunction(boolean distinct, String name, DataType<T> type, Field<?>... arguments) {
|
||||
this(distinct, DSL.name(name), type, arguments);
|
||||
}
|
||||
|
||||
DefaultAggregateFunction(boolean distinct, Name name, DataType<T> type, Field<?>... arguments) {
|
||||
super(distinct, name, type, arguments);
|
||||
|
||||
this.term = null;
|
||||
this.distinct = distinct;
|
||||
this.arguments = new QueryPartList<>(arguments);
|
||||
}
|
||||
|
||||
DefaultAggregateFunction(Term term, boolean distinct, DataType<T> type, Field<?>... arguments) {
|
||||
super(term.toName(), type);
|
||||
DefaultAggregateFunction(boolean distinct, Term term, DataType<T> type, Field<?>... arguments) {
|
||||
super(distinct, term.toName(), type, arguments);
|
||||
|
||||
this.term = term;
|
||||
this.distinct = distinct;
|
||||
this.arguments = new QueryPartList<>(arguments);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -181,162 +117,29 @@ class DefaultAggregateFunction<T> extends AbstractWindowFunction<T> implements
|
||||
@Override
|
||||
public /* final */ void accept(Context<?> ctx) {
|
||||
if (term == ARRAY_AGG && SUPPORT_ARRAY_AGG.contains(ctx.dialect())) {
|
||||
toSQLGroupConcat(ctx);
|
||||
toSQLFilterClause(ctx);
|
||||
toSQLArrayAgg(ctx);
|
||||
acceptFilterClause(ctx);
|
||||
acceptOverClause(ctx);
|
||||
}
|
||||
else if (term == LIST_AGG && SUPPORT_GROUP_CONCAT.contains(ctx.dialect())) {
|
||||
toSQLGroupConcat(ctx);
|
||||
}
|
||||
else if (term == LIST_AGG && SUPPORT_STRING_AGG .contains(ctx.dialect())) {
|
||||
toSQLStringAgg(ctx);
|
||||
toSQLFilterClause(ctx);
|
||||
acceptOverClause(ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
else if (term == MODE && ( ctx.family() == H2 || ctx.family() == POSTGRES)) {
|
||||
ctx.visit(mode().withinGroupOrderBy(DSL.field("{0}", arguments.get(0))));
|
||||
}
|
||||
else if (term == MEDIAN && ( ctx.family() == POSTGRES)) {
|
||||
Field<?>[] fields = new Field[arguments.size()];
|
||||
for (int i = 0; i < fields.length; i++)
|
||||
fields[i] = DSL.field("{0}", arguments.get(i));
|
||||
|
||||
ctx.visit(percentileCont(new BigDecimal("0.5")).withinGroupOrderBy(fields));
|
||||
}
|
||||
else if (term == PRODUCT) {
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
final Field<Integer> f = (Field) DSL.field("{0}", arguments.get(0).getDataType(), arguments.get(0));
|
||||
final Field<Integer> negatives = DSL.when(f.lt(zero()), inline(-1));
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
Field<BigDecimal> negativesSum = new CustomField<BigDecimal>("sum", NUMERIC) {
|
||||
@Override
|
||||
public void accept(Context<?> c) {
|
||||
c.visit(distinct
|
||||
? DSL.sumDistinct(negatives)
|
||||
: DSL.sum(negatives));
|
||||
|
||||
toSQLFilterClause(c);
|
||||
acceptOverClause(c);
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
Field<BigDecimal> zerosSum = new CustomField<BigDecimal>("sum", NUMERIC) {
|
||||
@Override
|
||||
public void accept(Context<?> c) {
|
||||
c.visit(DSL.sum(choose(f).when(zero(), one())));
|
||||
|
||||
toSQLFilterClause(c);
|
||||
acceptOverClause(c);
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
Field<BigDecimal> logarithmsSum = new CustomField<BigDecimal>("sum", NUMERIC) {
|
||||
@Override
|
||||
public void accept(Context<?> c) {
|
||||
Field<Integer> abs = DSL.abs(DSL.nullif(f, zero()));
|
||||
Field<BigDecimal> ln =
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DSL.ln(abs);
|
||||
|
||||
c.visit(distinct
|
||||
? DSL.sumDistinct(ln)
|
||||
: DSL.sum(ln));
|
||||
|
||||
toSQLFilterClause(c);
|
||||
acceptOverClause(c);
|
||||
}
|
||||
};
|
||||
|
||||
ctx.visit(
|
||||
when(zerosSum.gt(inline(BigDecimal.ZERO)), zero())
|
||||
.when(negativesSum.mod(inline(2)).lt(inline(BigDecimal.ZERO)), inline(-1))
|
||||
.otherwise(one()).mul(DSL.exp(logarithmsSum))
|
||||
);
|
||||
}
|
||||
else {
|
||||
toSQLArguments(ctx);
|
||||
toSQLKeepDenseRankOrderByClause(ctx);
|
||||
toSQLWithinGroupClause(ctx);
|
||||
toSQLFilterClause(ctx);
|
||||
acceptFilterClause(ctx);
|
||||
acceptOverClause(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* [#1275] <code>LIST_AGG</code> emulation for Postgres, Sybase
|
||||
* <code>ARRAY_AGG</code>
|
||||
*/
|
||||
final void toSQLStringAgg(Context<?> ctx) {
|
||||
final void toSQLArrayAgg(Context<?> ctx) {
|
||||
toSQLFunctionName(ctx);
|
||||
ctx.sql('(');
|
||||
|
||||
if (distinct)
|
||||
ctx.visit(K_DISTINCT).sql(' ');
|
||||
|
||||
// The explicit cast is needed in Postgres
|
||||
ctx.visit(castIfNeeded((Field<?>) arguments.get(0), String.class));
|
||||
|
||||
if (arguments.size() > 1)
|
||||
ctx.sql(", ").visit(arguments.get(1));
|
||||
else
|
||||
ctx.sql(", ''");
|
||||
acceptArguments1(ctx, new QueryPartList<>(Arrays.asList(arguments.get(0))));
|
||||
|
||||
if (!Tools.isEmpty(withinGroupOrderBy))
|
||||
ctx.sql(' ').visit(K_ORDER_BY).sql(' ')
|
||||
@ -345,39 +148,6 @@ class DefaultAggregateFunction<T> extends AbstractWindowFunction<T> implements
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
/**
|
||||
* [#1273] <code>LIST_AGG</code> emulation for MySQL
|
||||
*/
|
||||
final void toSQLGroupConcat(Context<?> ctx) {
|
||||
toSQLFunctionName(ctx);
|
||||
ctx.sql('(');
|
||||
toSQLArguments1(ctx, new QueryPartList<>(Arrays.asList(arguments.get(0))));
|
||||
|
||||
if (!Tools.isEmpty(withinGroupOrderBy))
|
||||
ctx.sql(' ').visit(K_ORDER_BY).sql(' ')
|
||||
.visit(withinGroupOrderBy);
|
||||
|
||||
if (arguments.size() > 1)
|
||||
if (ctx.family() == SQLITE)
|
||||
ctx.sql(", ").visit(arguments.get(1));
|
||||
else
|
||||
ctx.sql(' ').visit(K_SEPARATOR).sql(' ')
|
||||
.visit(arguments.get(1));
|
||||
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
final void toSQLFilterClause(Context<?> ctx) {
|
||||
if (filter != null && SUPPORT_FILTER.contains(ctx.dialect()))
|
||||
ctx.sql(' ')
|
||||
.visit(K_FILTER)
|
||||
.sql(" (")
|
||||
.visit(K_WHERE)
|
||||
.sql(' ')
|
||||
.visit(filter)
|
||||
.sql(')');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render <code>KEEP (DENSE_RANK [FIRST | LAST] ORDER BY {...})</code> clause
|
||||
*/
|
||||
@ -415,172 +185,14 @@ class DefaultAggregateFunction<T> extends AbstractWindowFunction<T> implements
|
||||
final void toSQLArguments(Context<?> ctx) {
|
||||
toSQLFunctionName(ctx);
|
||||
ctx.sql('(');
|
||||
toSQLArguments0(ctx);
|
||||
acceptArguments0(ctx);
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
final void toSQLArguments0(Context<?> ctx) {
|
||||
toSQLArguments1(ctx, arguments);
|
||||
}
|
||||
|
||||
final void toSQLArguments1(Context<?> ctx, QueryPartList<Field<?>> args) {
|
||||
if (distinct) {
|
||||
ctx.visit(K_DISTINCT).sql(' ');
|
||||
|
||||
// [#2883][#9109] PostgreSQL and H2 can use the DISTINCT keyword with formal row value expressions.
|
||||
if (args.size() > 1 && SUPPORT_DISTINCT_RVE.contains(ctx.family()))
|
||||
ctx.sql('(');
|
||||
}
|
||||
|
||||
if (!args.isEmpty()) {
|
||||
if (filter == null || SUPPORT_FILTER.contains(ctx.dialect())) {
|
||||
ctx.visit(args);
|
||||
}
|
||||
else {
|
||||
QueryPartList<Field<?>> expressions = new QueryPartList<>();
|
||||
|
||||
for (Field<?> argument : args)
|
||||
expressions.add(DSL.when(filter, argument == ASTERISK ? one() : argument));
|
||||
|
||||
ctx.visit(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
if (distinct)
|
||||
if (args.size() > 1 && SUPPORT_DISTINCT_RVE.contains(ctx.family()))
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
final void toSQLFunctionName(Context<?> ctx) {
|
||||
if (term != null)
|
||||
ctx.sql(term.translate(ctx.dialect()));
|
||||
else
|
||||
ctx.sql(getName());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX aggregate and window function fluent API methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
final QueryPartList<Field<?>> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(OrderField<?>... fields) {
|
||||
return withinGroupOrderBy(Arrays.asList(fields));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(Collection<? extends OrderField<?>> fields) {
|
||||
if (withinGroupOrderBy == null)
|
||||
withinGroupOrderBy = new SortFieldList();
|
||||
|
||||
withinGroupOrderBy.addAll(Tools.sortFields(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Condition c) {
|
||||
filter = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Condition... conditions) {
|
||||
return filterWhere(Arrays.asList(conditions));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Collection<? extends Condition> conditions) {
|
||||
ConditionProviderImpl c = new ConditionProviderImpl();
|
||||
c.addConditions(conditions);
|
||||
return filterWhere(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Field<Boolean> field) {
|
||||
return filterWhere(condition(field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(Boolean field) {
|
||||
return filterWhere(condition(field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(SQL sql) {
|
||||
return filterWhere(condition(sql));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(String sql) {
|
||||
return filterWhere(condition(sql));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(String sql, Object... bindings) {
|
||||
return filterWhere(condition(sql, bindings));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowBeforeOverStep<T> filterWhere(String sql, QueryPart... parts) {
|
||||
return filterWhere(condition(sql, parts));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DefaultAggregateFunction<T> orderBy(OrderField<?>... fields) {
|
||||
if (windowSpecification != null)
|
||||
windowSpecification.orderBy(fields);
|
||||
else
|
||||
withinGroupOrderBy(fields);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DefaultAggregateFunction<T> orderBy(Collection<? extends OrderField<?>> fields) {
|
||||
if (windowSpecification != null)
|
||||
windowSpecification.orderBy(fields);
|
||||
else
|
||||
withinGroupOrderBy(fields);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,12 +89,12 @@ final class GroupConcat extends AbstractFunction<String> implements GroupConcatO
|
||||
|
||||
@Override
|
||||
final Field<String> getFunction0(Configuration configuration) {
|
||||
DefaultAggregateFunction<String> result;
|
||||
ListAgg result;
|
||||
|
||||
if (separator == null)
|
||||
result = new DefaultAggregateFunction<>(Term.LIST_AGG, distinct, SQLDataType.VARCHAR, field, inline(","));
|
||||
result = new ListAgg(distinct, field, inline(","));
|
||||
else
|
||||
result = new DefaultAggregateFunction<>(Term.LIST_AGG, distinct, SQLDataType.VARCHAR, field, inline(separator));
|
||||
result = new ListAgg(distinct, field, inline(separator));
|
||||
|
||||
|
||||
|
||||
|
||||
231
jOOQ/src/main/java/org/jooq/impl/ListAgg.java
Normal file
231
jOOQ/src/main/java/org/jooq/impl/ListAgg.java
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
import static org.jooq.SQLDialect.MARIADB;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.MYSQL;
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
import static org.jooq.SQLDialect.SQLITE;
|
||||
// ...
|
||||
// ...
|
||||
import static org.jooq.impl.Keywords.F_CONCAT;
|
||||
import static org.jooq.impl.Keywords.F_SUBSTR;
|
||||
import static org.jooq.impl.Keywords.F_XMLAGG;
|
||||
import static org.jooq.impl.Keywords.F_XMLSERIALIZE;
|
||||
import static org.jooq.impl.Keywords.F_XMLTEXT;
|
||||
import static org.jooq.impl.Keywords.K_AS;
|
||||
import static org.jooq.impl.Keywords.K_DISTINCT;
|
||||
import static org.jooq.impl.Keywords.K_ORDER_BY;
|
||||
import static org.jooq.impl.Keywords.K_SEPARATOR;
|
||||
import static org.jooq.impl.Names.N_GROUP_CONCAT;
|
||||
import static org.jooq.impl.Names.N_LIST;
|
||||
import static org.jooq.impl.Names.N_LISTAGG;
|
||||
import static org.jooq.impl.Names.N_STRING_AGG;
|
||||
import static org.jooq.impl.Tools.castIfNeeded;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
// ...
|
||||
import org.jooq.SQLDialect;
|
||||
// ...
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class ListAgg extends DefaultAggregateFunction<String> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -1760389929938136896L;
|
||||
private static final Set<SQLDialect> SUPPORT_GROUP_CONCAT = SQLDialect.supportedBy(CUBRID, H2, HSQLDB, MARIADB, MYSQL, SQLITE);
|
||||
private static final Set<SQLDialect> SUPPORT_STRING_AGG = SQLDialect.supportedBy(POSTGRES);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ListAgg(boolean distinct, Field<?> arg) {
|
||||
super(distinct, N_LISTAGG, SQLDataType.VARCHAR, arg);
|
||||
}
|
||||
|
||||
ListAgg(boolean distinct, Field<?> arg, Field<String> separator) {
|
||||
super(distinct, N_LISTAGG, SQLDataType.VARCHAR, arg, separator);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
if (SUPPORT_GROUP_CONCAT.contains(ctx.dialect())) {
|
||||
acceptGroupConcat(ctx);
|
||||
}
|
||||
else if (SUPPORT_STRING_AGG.contains(ctx.dialect())) {
|
||||
acceptStringAgg(ctx);
|
||||
acceptFilterClause(ctx);
|
||||
acceptOverClause(ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
else {
|
||||
super.accept(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [#1273] <code>LIST_AGG</code> emulation for MySQL
|
||||
*/
|
||||
private final void acceptGroupConcat(Context<?> ctx) {
|
||||
ctx.visit(N_GROUP_CONCAT).sql('(');
|
||||
acceptArguments1(ctx, new QueryPartList<>(Arrays.asList(arguments.get(0))));
|
||||
|
||||
if (!Tools.isEmpty(withinGroupOrderBy))
|
||||
ctx.sql(' ').visit(K_ORDER_BY).sql(' ')
|
||||
.visit(withinGroupOrderBy);
|
||||
|
||||
if (arguments.size() > 1)
|
||||
if (ctx.family() == SQLITE)
|
||||
ctx.sql(", ").visit(arguments.get(1));
|
||||
else
|
||||
ctx.sql(' ').visit(K_SEPARATOR).sql(' ')
|
||||
.visit(arguments.get(1));
|
||||
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
/**
|
||||
* [#1275] <code>LIST_AGG</code> emulation for Postgres, Sybase
|
||||
*/
|
||||
private final void acceptStringAgg(Context<?> ctx) {
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
ctx.visit(N_STRING_AGG);
|
||||
break;
|
||||
}
|
||||
|
||||
ctx.sql('(');
|
||||
|
||||
if (distinct)
|
||||
ctx.visit(K_DISTINCT).sql(' ');
|
||||
|
||||
// The explicit cast is needed in Postgres
|
||||
ctx.visit(castIfNeeded((Field<?>) arguments.get(0), String.class));
|
||||
|
||||
if (arguments.size() > 1)
|
||||
ctx.sql(", ").visit(arguments.get(1));
|
||||
else
|
||||
ctx.sql(", ''");
|
||||
|
||||
if (!Tools.isEmpty(withinGroupOrderBy))
|
||||
ctx.sql(' ').visit(K_ORDER_BY).sql(' ')
|
||||
.visit(withinGroupOrderBy);
|
||||
|
||||
ctx.sql(')');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
79
jOOQ/src/main/java/org/jooq/impl/Median.java
Normal file
79
jOOQ/src/main/java/org/jooq/impl/Median.java
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
import static org.jooq.impl.DSL.percentileCont;
|
||||
import static org.jooq.impl.Names.N_MEDIAN;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.SQLDialect;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class Median extends DefaultAggregateFunction<BigDecimal> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -7378732863724089028L;
|
||||
private static final Set<SQLDialect> EMULATE_WITH_PERCENTILES = SQLDialect.supportedBy(POSTGRES);
|
||||
|
||||
Median(Field<? extends Number> arg) {
|
||||
super(false, N_MEDIAN, SQLDataType.NUMERIC, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
if (EMULATE_WITH_PERCENTILES.contains(ctx.dialect())) {
|
||||
Field<?>[] fields = new Field[arguments.size()];
|
||||
for (int i = 0; i < fields.length; i++)
|
||||
fields[i] = DSL.field("{0}", arguments.get(i));
|
||||
|
||||
ctx.visit(percentileCont(new BigDecimal("0.5")).withinGroupOrderBy(fields));
|
||||
}
|
||||
else
|
||||
super.accept(ctx);
|
||||
}
|
||||
}
|
||||
@ -78,15 +78,19 @@ final class Names {
|
||||
static final Name N_FLOOR = DSL.name("floor");
|
||||
static final Name N_FUNCTION = DSL.name("function");
|
||||
static final Name N_GENERATE_SERIES = DSL.name("generate_series");
|
||||
static final Name N_GROUP_CONCAT = DSL.unquotedName("group_concat");
|
||||
static final Name N_IIF = DSL.name("iif");
|
||||
static final Name N_JOIN = DSL.name("join");
|
||||
static final Name N_JSON_ARRAY = DSL.name("json_array");
|
||||
static final Name N_JSON_OBJECT = DSL.name("json_object");
|
||||
static final Name N_LEFT = DSL.name("left");
|
||||
static final Name N_LIST = DSL.unquotedName("list");
|
||||
static final Name N_LISTAGG = DSL.unquotedName("listagg");
|
||||
static final Name N_LOWER = DSL.name("lower");
|
||||
static final Name N_LPAD = DSL.name("lpad");
|
||||
static final Name N_LTRIM = DSL.name("ltrim");
|
||||
static final Name N_MD5 = DSL.name("md5");
|
||||
static final Name N_MEDIAN = DSL.name("median");
|
||||
static final Name N_MOD = DSL.name("mod");
|
||||
static final Name N_NEXTVAL = DSL.name("nextval");
|
||||
static final Name N_NOT = DSL.name("not");
|
||||
@ -99,6 +103,7 @@ final class Names {
|
||||
static final Name N_POSITION = DSL.name("position");
|
||||
static final Name N_POWER = DSL.name("power");
|
||||
static final Name N_PRIOR = DSL.name("prior");
|
||||
static final Name N_PRODUCT = DSL.unquotedName("product");
|
||||
static final Name N_RANDOM = DSL.name("rand");
|
||||
static final Name N_REVERSE = DSL.name("reverse");
|
||||
static final Name N_RIGHT = DSL.name("right");
|
||||
@ -114,6 +119,7 @@ final class Names {
|
||||
static final Name N_SINH = DSL.name("sinh");
|
||||
static final Name N_SPACE = DSL.name("space");
|
||||
static final Name N_SQRT = DSL.name("sqrt");
|
||||
static final Name N_STRING_AGG = DSL.unquotedName("string_agg");
|
||||
static final Name N_SUBSTRING = DSL.name("substring");
|
||||
static final Name N_SYSTEM_TIME = DSL.unquotedName("system_time");
|
||||
static final Name N_T = DSL.name("t");
|
||||
|
||||
127
jOOQ/src/main/java/org/jooq/impl/Product.java
Normal file
127
jOOQ/src/main/java/org/jooq/impl/Product.java
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.choose;
|
||||
import static org.jooq.impl.DSL.inline;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.when;
|
||||
import static org.jooq.impl.DSL.zero;
|
||||
import static org.jooq.impl.Names.N_PRODUCT;
|
||||
import static org.jooq.impl.SQLDataType.NUMERIC;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Field;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class Product extends AbstractAggregateFunction<BigDecimal> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = 1027749554935573353L;
|
||||
|
||||
Product(boolean distinct, Field<?>... arguments) {
|
||||
super(distinct, N_PRODUCT, NUMERIC, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
final Field<Integer> f = (Field) DSL.field("{0}", arguments.get(0).getDataType(), arguments.get(0));
|
||||
final Field<Integer> negatives = DSL.when(f.lt(zero()), inline(-1));
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
Field<BigDecimal> negativesSum = new CustomField<BigDecimal>("sum", NUMERIC) {
|
||||
@Override
|
||||
public void accept(Context<?> c) {
|
||||
c.visit(distinct
|
||||
? DSL.sumDistinct(negatives)
|
||||
: DSL.sum(negatives));
|
||||
|
||||
acceptFilterClause(c);
|
||||
acceptOverClause(c);
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
Field<BigDecimal> zerosSum = new CustomField<BigDecimal>("sum", NUMERIC) {
|
||||
@Override
|
||||
public void accept(Context<?> c) {
|
||||
c.visit(DSL.sum(choose(f).when(zero(), one())));
|
||||
|
||||
acceptFilterClause(c);
|
||||
acceptOverClause(c);
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
Field<BigDecimal> logarithmsSum = new CustomField<BigDecimal>("sum", NUMERIC) {
|
||||
@Override
|
||||
public void accept(Context<?> c) {
|
||||
Field<Integer> abs = DSL.abs(DSL.nullif(f, zero()));
|
||||
Field<BigDecimal> ln =
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DSL.ln(abs);
|
||||
|
||||
c.visit(distinct
|
||||
? DSL.sumDistinct(ln)
|
||||
: DSL.sum(ln));
|
||||
|
||||
acceptFilterClause(c);
|
||||
acceptOverClause(c);
|
||||
}
|
||||
};
|
||||
|
||||
ctx.visit(
|
||||
when(zerosSum.gt(inline(BigDecimal.ZERO)), zero())
|
||||
.when(negativesSum.mod(inline(2)).lt(inline(BigDecimal.ZERO)), inline(-1))
|
||||
.otherwise(one()).mul(DSL.exp(logarithmsSum))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -126,41 +126,6 @@ enum Term {
|
||||
|
||||
|
||||
|
||||
LIST_AGG {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case CUBRID:
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
case MARIADB:
|
||||
case MYSQL:
|
||||
case SQLITE:
|
||||
return "group_concat";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
case POSTGRES:
|
||||
return "string_agg";
|
||||
}
|
||||
|
||||
return "listagg";
|
||||
}
|
||||
},
|
||||
MEDIAN,
|
||||
MODE {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
@ -201,7 +166,6 @@ enum Term {
|
||||
return "octet_length";
|
||||
}
|
||||
},
|
||||
PRODUCT,
|
||||
STDDEV_POP {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user