[#1268] Add Factory.field(String, QueryPart...) to generate custom clauses - Some simplifications
This commit is contained in:
parent
7d78b0a23a
commit
e1220a5e75
@ -1,126 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.AggregateFunction;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.OrderedAggregateFunction;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.SortField;
|
||||
|
||||
class AggregateFunctionImpl<T> extends Function<T> implements OrderedAggregateFunction<T>, AggregateFunction<T> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = 1952351506930280715L;
|
||||
|
||||
private final boolean distinct;
|
||||
private final SortFieldList withinGroupOrderBy;
|
||||
|
||||
AggregateFunctionImpl(String name, DataType<T> type, Field<?>... arguments) {
|
||||
this(name, false, type, arguments);
|
||||
}
|
||||
|
||||
AggregateFunctionImpl(Term term, DataType<T> type, Field<?>... arguments) {
|
||||
this(term, false, type, arguments);
|
||||
}
|
||||
|
||||
AggregateFunctionImpl(String name, boolean distinct, DataType<T> type, Field<?>... arguments) {
|
||||
super(name, type, arguments);
|
||||
|
||||
this.distinct = distinct;
|
||||
this.withinGroupOrderBy = new SortFieldList();
|
||||
}
|
||||
|
||||
AggregateFunctionImpl(Term term, boolean distinct, DataType<T> type, Field<?>... arguments) {
|
||||
super(term, type, arguments);
|
||||
|
||||
this.distinct = distinct;
|
||||
this.withinGroupOrderBy = new SortFieldList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(Field<?>... fields) {
|
||||
withinGroupOrderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(SortField<?>... fields) {
|
||||
withinGroupOrderBy.addAll(Arrays.asList(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(Collection<SortField<?>> fields) {
|
||||
withinGroupOrderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> over() {
|
||||
if (getTerm() != null) {
|
||||
return new WindowFunction<T>(getTerm(), getDataType(), withinGroupOrderBy, getArguments());
|
||||
}
|
||||
else {
|
||||
return new WindowFunction<T>(getName(), getDataType(), withinGroupOrderBy, getArguments());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void toSQLField(RenderContext context, QueryPart field) {
|
||||
if (distinct) {
|
||||
context.keyword("distinct ");
|
||||
}
|
||||
|
||||
super.toSQLField(context, field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void toSQLSuffix(RenderContext context) {
|
||||
if (!withinGroupOrderBy.isEmpty()) {
|
||||
context.keyword(" within group (order by ")
|
||||
.sql(withinGroupOrderBy)
|
||||
.sql(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,8 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Factory.function;
|
||||
|
||||
import org.jooq.CaseConditionStep;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Field;
|
||||
@ -70,7 +72,7 @@ class Decode<T, Z> extends AbstractFunction<Z> {
|
||||
|
||||
// Oracle actually has this function
|
||||
case ORACLE: {
|
||||
return new Function<Z>("decode", getDataType(), getArguments());
|
||||
return function("decode", getDataType(), getArguments());
|
||||
}
|
||||
|
||||
// Other dialects simulate it with a CASE ... WHEN expression
|
||||
|
||||
@ -4070,7 +4070,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<Integer> count(Field<?> field) {
|
||||
return new AggregateFunctionImpl<Integer>("count", SQLDataType.INTEGER, nullSafe(field));
|
||||
return new Function<Integer>("count", SQLDataType.INTEGER, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4078,7 +4078,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<Integer> countDistinct(Field<?> field) {
|
||||
return new AggregateFunctionImpl<Integer>("count", true, SQLDataType.INTEGER, nullSafe(field));
|
||||
return new Function<Integer>("count", true, SQLDataType.INTEGER, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4086,7 +4086,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static <T> AggregateFunction<T> max(Field<T> field) {
|
||||
return new AggregateFunctionImpl<T>("max", nullSafeDataType(field), nullSafe(field));
|
||||
return new Function<T>("max", nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4094,7 +4094,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static <T> AggregateFunction<T> maxDistinct(Field<T> field) {
|
||||
return new AggregateFunctionImpl<T>("max", true, nullSafeDataType(field), nullSafe(field));
|
||||
return new Function<T>("max", true, nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4102,7 +4102,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static <T> AggregateFunction<T> min(Field<T> field) {
|
||||
return new AggregateFunctionImpl<T>("min", nullSafeDataType(field), nullSafe(field));
|
||||
return new Function<T>("min", nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4110,7 +4110,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static <T> AggregateFunction<T> minDistinct(Field<T> field) {
|
||||
return new AggregateFunctionImpl<T>("min", true, nullSafeDataType(field), nullSafe(field));
|
||||
return new Function<T>("min", true, nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4118,7 +4118,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<BigDecimal> sum(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>("sum", SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>("sum", SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4126,7 +4126,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<BigDecimal> sumDistinct(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>("sum", true, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>("sum", true, SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4134,7 +4134,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<BigDecimal> avg(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>("avg", SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>("avg", SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4142,7 +4142,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support
|
||||
public static AggregateFunction<BigDecimal> avgDistinct(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>("avg", true, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>("avg", true, SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4157,7 +4157,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ HSQLDB, ORACLE, SYBASE })
|
||||
public static AggregateFunction<BigDecimal> median(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>("median", SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>("median", SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4179,7 +4179,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
|
||||
public static AggregateFunction<BigDecimal> stddevPop(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>(Term.STDDEV_POP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>(Term.STDDEV_POP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4201,7 +4201,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
|
||||
public static AggregateFunction<BigDecimal> stddevSamp(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>(Term.STDDEV_SAMP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>(Term.STDDEV_SAMP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4223,7 +4223,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
|
||||
public static AggregateFunction<BigDecimal> varPop(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>(Term.VAR_POP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>(Term.VAR_POP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4243,7 +4243,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
|
||||
public static AggregateFunction<BigDecimal> varSamp(Field<? extends Number> field) {
|
||||
return new AggregateFunctionImpl<BigDecimal>(Term.VAR_SAMP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
return new Function<BigDecimal>(Term.VAR_SAMP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4251,7 +4251,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support(ORACLE)
|
||||
public static OrderedAggregateFunction<String> listAgg(Field<?> field) {
|
||||
return new AggregateFunctionImpl<String>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field));
|
||||
return new Function<String>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4259,7 +4259,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support(ORACLE)
|
||||
public static OrderedAggregateFunction<String> listAgg(Field<?> field, String delimiter) {
|
||||
return new AggregateFunctionImpl<String>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field), literal("'" + delimiter.replace("'", "''") + "'"));
|
||||
return new Function<String>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field), literal("'" + delimiter.replace("'", "''") + "'"));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -4274,7 +4274,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE, SQLSERVER, SYBASE })
|
||||
public static WindowOverStep<Integer> rowNumber() {
|
||||
return new WindowFunction<Integer>("row_number", SQLDataType.INTEGER);
|
||||
return new Function<Integer>("row_number", SQLDataType.INTEGER);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4285,7 +4285,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE, SQLSERVER, SYBASE })
|
||||
public static WindowOverStep<Integer> rank() {
|
||||
return new WindowFunction<Integer>("rank", SQLDataType.INTEGER);
|
||||
return new Function<Integer>("rank", SQLDataType.INTEGER);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4296,7 +4296,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE, SQLSERVER, SYBASE })
|
||||
public static WindowOverStep<Integer> denseRank() {
|
||||
return new WindowFunction<Integer>("dense_rank", SQLDataType.INTEGER);
|
||||
return new Function<Integer>("dense_rank", SQLDataType.INTEGER);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4307,7 +4307,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ POSTGRES, ORACLE, SYBASE })
|
||||
public static WindowOverStep<BigDecimal> percentRank() {
|
||||
return new WindowFunction<BigDecimal>("percent_rank", SQLDataType.NUMERIC);
|
||||
return new Function<BigDecimal>("percent_rank", SQLDataType.NUMERIC);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4318,7 +4318,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ POSTGRES, ORACLE, SYBASE })
|
||||
public static WindowOverStep<BigDecimal> cumeDist() {
|
||||
return new WindowFunction<BigDecimal>("cume_dist", SQLDataType.NUMERIC);
|
||||
return new Function<BigDecimal>("cume_dist", SQLDataType.NUMERIC);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4329,7 +4329,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ POSTGRES, ORACLE, SQLSERVER })
|
||||
public static WindowOverStep<Integer> ntile(int number) {
|
||||
return new WindowFunction<Integer>("ntile", SQLDataType.INTEGER, field("" + number, Integer.class));
|
||||
return new Function<Integer>("ntile", SQLDataType.INTEGER, field("" + number, Integer.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4340,7 +4340,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
|
||||
public static <T> WindowIgnoreNullsStep<T> firstValue(Field<T> field) {
|
||||
return new WindowFunction<T>("first_value", nullSafeDataType(field), nullSafe(field));
|
||||
return new Function<T>("first_value", nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4351,7 +4351,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
|
||||
public static <T> WindowIgnoreNullsStep<T> lastValue(Field<T> field) {
|
||||
return new WindowFunction<T>("last_value", nullSafeDataType(field), nullSafe(field));
|
||||
return new Function<T>("last_value", nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4362,7 +4362,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE })
|
||||
public static <T> WindowIgnoreNullsStep<T> lead(Field<T> field) {
|
||||
return new WindowFunction<T>("lead", nullSafeDataType(field), nullSafe(field));
|
||||
return new Function<T>("lead", nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4373,7 +4373,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE })
|
||||
public static <T> WindowIgnoreNullsStep<T> lead(Field<T> field, int offset) {
|
||||
return new WindowFunction<T>("lead", nullSafeDataType(field), nullSafe(field), literal(offset));
|
||||
return new Function<T>("lead", nullSafeDataType(field), nullSafe(field), literal(offset));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4399,7 +4399,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE })
|
||||
public static <T> WindowIgnoreNullsStep<T> lead(Field<T> field, int offset, Field<T> defaultValue) {
|
||||
return new WindowFunction<T>("lead", nullSafeDataType(field), nullSafe(field), literal(offset), nullSafe(defaultValue));
|
||||
return new Function<T>("lead", nullSafeDataType(field), nullSafe(field), literal(offset), nullSafe(defaultValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4410,7 +4410,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE })
|
||||
public static <T> WindowIgnoreNullsStep<T> lag(Field<T> field) {
|
||||
return new WindowFunction<T>("lag", nullSafeDataType(field), nullSafe(field));
|
||||
return new Function<T>("lag", nullSafeDataType(field), nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4421,7 +4421,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE })
|
||||
public static <T> WindowIgnoreNullsStep<T> lag(Field<T> field, int offset) {
|
||||
return new WindowFunction<T>("lag", nullSafeDataType(field), nullSafe(field), literal(offset));
|
||||
return new Function<T>("lag", nullSafeDataType(field), nullSafe(field), literal(offset));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4447,7 +4447,7 @@ public class Factory implements FactoryOperations {
|
||||
*/
|
||||
@Support({ DB2, POSTGRES, ORACLE })
|
||||
public static <T> WindowIgnoreNullsStep<T> lag(Field<T> field, int offset, Field<T> defaultValue) {
|
||||
return new WindowFunction<T>("lag", nullSafeDataType(field), nullSafe(field), literal(offset), nullSafe(defaultValue));
|
||||
return new Function<T>("lag", nullSafeDataType(field), nullSafe(field), literal(offset), nullSafe(defaultValue));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -36,7 +36,6 @@
|
||||
|
||||
package org.jooq.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@ -63,7 +62,7 @@ class FieldList extends NamedQueryPartList<Field<?>> implements FieldProvider {
|
||||
}
|
||||
|
||||
FieldList(Field<?>... wrappedList) {
|
||||
super(Arrays.asList(wrappedList));
|
||||
super(wrappedList);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@ -36,59 +36,224 @@
|
||||
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Factory.one;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.jooq.AggregateFunction;
|
||||
import org.jooq.Attachable;
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.OrderedAggregateFunction;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.SortField;
|
||||
import org.jooq.WindowFinalStep;
|
||||
import org.jooq.WindowIgnoreNullsStep;
|
||||
import org.jooq.WindowOrderByStep;
|
||||
import org.jooq.WindowOverStep;
|
||||
import org.jooq.WindowPartitionByStep;
|
||||
import org.jooq.WindowRowsAndStep;
|
||||
import org.jooq.WindowRowsStep;
|
||||
|
||||
/**
|
||||
* A field that handles built-in functions, aggregate functions, and window
|
||||
* functions.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class Function<T> extends AbstractField<T> {
|
||||
class Function<T> extends AbstractField<T> implements
|
||||
|
||||
private static final long serialVersionUID = 347252741712134044L;
|
||||
// Cascading interface implementations for aggregate and window function behaviour
|
||||
OrderedAggregateFunction<T>,
|
||||
AggregateFunction<T>,
|
||||
WindowIgnoreNullsStep<T>,
|
||||
WindowPartitionByStep<T>,
|
||||
WindowRowsStep<T>,
|
||||
WindowRowsAndStep<T>
|
||||
{
|
||||
|
||||
private final QueryPart[] arguments;
|
||||
private final Term term;
|
||||
private static final long serialVersionUID = 347252741712134044L;
|
||||
|
||||
private final QueryPartList<QueryPart> arguments;
|
||||
private final Term term;
|
||||
private final boolean distinct;
|
||||
private final SortFieldList withinGroupOrderBy;
|
||||
private final FieldList partitionBy;
|
||||
private final SortFieldList orderBy;
|
||||
|
||||
private boolean over;
|
||||
private boolean partitionByOne;
|
||||
private boolean ignoreNulls;
|
||||
private boolean respectNulls;
|
||||
private Integer rowsStart;
|
||||
private Integer rowsEnd;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Constructors
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Function(String name, DataType<T> type, QueryPart... arguments) {
|
||||
super(name, type);
|
||||
|
||||
this.arguments = arguments;
|
||||
this.term = null;
|
||||
this(name, false, type, arguments);
|
||||
}
|
||||
|
||||
Function(Term term, DataType<T> type, QueryPart... arguments) {
|
||||
this(term, false, type, arguments);
|
||||
}
|
||||
|
||||
Function(String name, boolean distinct, DataType<T> type, QueryPart... arguments) {
|
||||
super(name, type);
|
||||
|
||||
this.term = null;
|
||||
this.distinct = distinct;
|
||||
this.arguments = new QueryPartList<QueryPart>(arguments);
|
||||
this.withinGroupOrderBy = new SortFieldList();
|
||||
this.partitionBy = new FieldList();
|
||||
this.orderBy = new SortFieldList();
|
||||
}
|
||||
|
||||
Function(Term term, boolean distinct, DataType<T> type, QueryPart... arguments) {
|
||||
super(term.name().toLowerCase(), type);
|
||||
|
||||
this.arguments = arguments;
|
||||
this.term = term;
|
||||
this.distinct = distinct;
|
||||
this.arguments = new QueryPartList<QueryPart>(arguments);
|
||||
this.withinGroupOrderBy = new SortFieldList();
|
||||
this.partitionBy = new FieldList();
|
||||
this.orderBy = new SortFieldList();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX QueryPart API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final List<Attachable> getAttachables() {
|
||||
return getAttachables(arguments);
|
||||
return getAttachables(arguments, withinGroupOrderBy, partitionBy, orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext context) {
|
||||
context.sql(getFNName(context.getDialect()));
|
||||
context.sql("(");
|
||||
toSQLArguments(context);
|
||||
toSQLWithinGroupClause(context);
|
||||
toSQLOverClause(context);
|
||||
}
|
||||
|
||||
String separator = "";
|
||||
for (QueryPart field : arguments) {
|
||||
context.sql(separator);
|
||||
toSQLField(context, field);
|
||||
private void toSQLOverClause(RenderContext context) {
|
||||
if (!over) return;
|
||||
|
||||
separator = ", ";
|
||||
String glue = "";
|
||||
context.keyword(" over (");
|
||||
if (!partitionBy.isEmpty()) {
|
||||
if (partitionByOne && context.getDialect() == SQLDialect.SYBASE) {
|
||||
// Ignore partition clause. Sybase does not support this construct
|
||||
}
|
||||
else {
|
||||
context.sql(glue)
|
||||
.keyword("partition by ")
|
||||
.sql(partitionBy);
|
||||
|
||||
glue = " ";
|
||||
}
|
||||
}
|
||||
|
||||
if (!orderBy.isEmpty()) {
|
||||
context.sql(glue)
|
||||
.keyword("order by ");
|
||||
|
||||
switch (context.getDialect()) {
|
||||
|
||||
// SQL Server and Sybase don't allow for fully qualified fields
|
||||
// in the ORDER BY clause of an analytic expression
|
||||
case SQLSERVER: // No break
|
||||
case SYBASE: {
|
||||
for (SortField<?> f : orderBy) {
|
||||
SortFieldImpl<?> field = (SortFieldImpl<?>) f;
|
||||
field.toSQLInAnalyticClause(context);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
context.sql(orderBy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glue = " ";
|
||||
}
|
||||
|
||||
if (rowsStart != null) {
|
||||
context.sql(glue);
|
||||
context.keyword("rows ");
|
||||
|
||||
if (rowsEnd != null) {
|
||||
context.keyword("between ");
|
||||
toSQLRows(context, rowsStart);
|
||||
|
||||
context.keyword(" and ");
|
||||
toSQLRows(context, rowsEnd);
|
||||
}
|
||||
else {
|
||||
toSQLRows(context, rowsStart);
|
||||
}
|
||||
|
||||
glue = " ";
|
||||
}
|
||||
|
||||
context.sql(")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Render <code>WITHIN GROUP (ORDER BY ..)</code> clause
|
||||
*/
|
||||
private void toSQLWithinGroupClause(RenderContext context) {
|
||||
if (!withinGroupOrderBy.isEmpty()) {
|
||||
context.keyword(" within group (order by ")
|
||||
.sql(withinGroupOrderBy)
|
||||
.sql(")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render function arguments and argument modifiers
|
||||
*/
|
||||
private void toSQLArguments(RenderContext context) {
|
||||
context.sql("(");
|
||||
|
||||
if (distinct) {
|
||||
context.keyword("distinct ");
|
||||
}
|
||||
|
||||
if (!arguments.isEmpty()) {
|
||||
context.sql(arguments);
|
||||
}
|
||||
|
||||
if (ignoreNulls) {
|
||||
if (context.getDialect() == SQLDialect.DB2) {
|
||||
context.sql(", 'IGNORE NULLS'");
|
||||
}
|
||||
else {
|
||||
context.keyword(" ignore nulls");
|
||||
}
|
||||
}
|
||||
else if (respectNulls) {
|
||||
if (context.getDialect() == SQLDialect.DB2) {
|
||||
context.sql(", 'RESPECT NULLS'");
|
||||
}
|
||||
else {
|
||||
context.keyword(" respect nulls");
|
||||
}
|
||||
}
|
||||
|
||||
context.sql(")");
|
||||
toSQLSuffix(context);
|
||||
}
|
||||
|
||||
private final String getFNName(SQLDialect dialect) {
|
||||
@ -100,29 +265,32 @@ class Function<T> extends AbstractField<T> {
|
||||
}
|
||||
}
|
||||
|
||||
final Term getTerm() {
|
||||
return term;
|
||||
private final void toSQLRows(RenderContext context, Integer rows) {
|
||||
if (rows == Integer.MIN_VALUE) {
|
||||
context.keyword("unbounded preceding");
|
||||
}
|
||||
else if (rows == Integer.MAX_VALUE) {
|
||||
context.keyword("unbounded following");
|
||||
}
|
||||
else if (rows < 0) {
|
||||
context.sql(-rows);
|
||||
context.keyword(" preceding");
|
||||
}
|
||||
else if (rows > 0) {
|
||||
context.sql(rows);
|
||||
context.keyword(" following");
|
||||
}
|
||||
else {
|
||||
context.keyword("current row");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render the argument field. This renders the field directly, by default.
|
||||
* Subclasses may override this method, if needed (e.g. to render
|
||||
* count(distinct [field])
|
||||
*/
|
||||
protected void toSQLField(RenderContext context, QueryPart field) {
|
||||
context.sql(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render additional SQL. Subclasses may override this method, if needed
|
||||
* (e.g. to render <code>WITHIN GROUP (ORDER BY ..)</code>)
|
||||
*/
|
||||
protected void toSQLSuffix(RenderContext context) {}
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {
|
||||
context.bind(arguments);
|
||||
context.bind((QueryPart) arguments)
|
||||
.bind((QueryPart) withinGroupOrderBy)
|
||||
.bind((QueryPart) partitionBy)
|
||||
.bind((QueryPart) orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -130,7 +298,170 @@ class Function<T> extends AbstractField<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
final QueryPart[] getArguments() {
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX aggregate and window function fluent API methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
final QueryPartList<QueryPart> getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(Field<?>... fields) {
|
||||
withinGroupOrderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(SortField<?>... fields) {
|
||||
withinGroupOrderBy.addAll(Arrays.asList(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<T> withinGroupOrderBy(Collection<SortField<?>> fields) {
|
||||
withinGroupOrderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowPartitionByStep<T> over() {
|
||||
over = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowOverStep<T> ignoreNulls() {
|
||||
ignoreNulls = true;
|
||||
respectNulls = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowOverStep<T> respectNulls() {
|
||||
ignoreNulls = false;
|
||||
respectNulls = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowOrderByStep<T> partitionBy(Field<?>... fields) {
|
||||
partitionBy.addAll(Arrays.asList(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowOrderByStep<T> partitionByOne() {
|
||||
partitionByOne = true;
|
||||
partitionBy.add(one());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowRowsStep<T> orderBy(Field<?>... fields) {
|
||||
orderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowRowsStep<T> orderBy(SortField<?>... fields) {
|
||||
orderBy.addAll(Arrays.asList(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowRowsStep<T> orderBy(Collection<SortField<?>> fields) {
|
||||
orderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> rowsUnboundedPreceding() {
|
||||
rowsStart = Integer.MIN_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> rowsPreceding(int number) {
|
||||
rowsStart = -number;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> rowsCurrentRow() {
|
||||
rowsStart = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> rowsUnboundedFollowing() {
|
||||
rowsStart = Integer.MAX_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> rowsFollowing(int number) {
|
||||
rowsStart = number;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowRowsAndStep<T> rowsBetweenUnboundedPreceding() {
|
||||
rowsUnboundedPreceding();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowRowsAndStep<T> rowsBetweenPreceding(int number) {
|
||||
rowsPreceding(number);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowRowsAndStep<T> rowsBetweenCurrentRow() {
|
||||
rowsCurrentRow();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowRowsAndStep<T> rowsBetweenUnboundedFollowing() {
|
||||
rowsUnboundedFollowing();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowRowsAndStep<T> rowsBetweenFollowing(int number) {
|
||||
rowsFollowing(number);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> andUnboundedPreceding() {
|
||||
rowsEnd = Integer.MIN_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> andPreceding(int number) {
|
||||
rowsEnd = -number;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> andCurrentRow() {
|
||||
rowsEnd = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> andUnboundedFollowing() {
|
||||
rowsEnd = Integer.MAX_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFinalStep<T> andFollowing(int number) {
|
||||
rowsEnd = number;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,4 +56,8 @@ class NamedQueryPartList<T extends NamedQueryPart> extends QueryPartList<T> {
|
||||
NamedQueryPartList(Collection<? extends T> wrappedList) {
|
||||
super(wrappedList);
|
||||
}
|
||||
|
||||
NamedQueryPartList(T... wrappedList) {
|
||||
super(wrappedList);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,8 +155,8 @@ implements
|
||||
// This loop finds all fields that are used in aggregate
|
||||
// functions. They're excluded from the GROUP BY clause
|
||||
for (Field<?> field : aggregateFunctions) {
|
||||
if (field instanceof AggregateFunctionImpl) {
|
||||
for (QueryPart argument : ((AggregateFunctionImpl<?>) field).getArguments()) {
|
||||
if (field instanceof Function) {
|
||||
for (QueryPart argument : ((Function<?>) field).getArguments()) {
|
||||
if (argument instanceof Field) {
|
||||
aggregatedFields.add((Field<?>) argument);
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -56,7 +57,7 @@ class QueryPartList<T extends QueryPart> extends AbstractQueryPart implements Li
|
||||
private final List<T> wrappedList = new ArrayList<T>();
|
||||
|
||||
QueryPartList() {
|
||||
this(null);
|
||||
this((Collection<T>) null);
|
||||
}
|
||||
|
||||
QueryPartList(Collection<? extends T> wrappedList) {
|
||||
@ -67,6 +68,11 @@ class QueryPartList<T extends QueryPart> extends AbstractQueryPart implements Li
|
||||
}
|
||||
}
|
||||
|
||||
QueryPartList(T... wrappedList) {
|
||||
this(Arrays.asList(wrappedList));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final List<Attachable> getAttachables() {
|
||||
return getAttachables(this);
|
||||
|
||||
@ -71,7 +71,7 @@ class SQLClause<T> extends AbstractField<T> {
|
||||
|
||||
@Override
|
||||
public final List<Attachable> getAttachables() {
|
||||
return null;
|
||||
return getAttachables(parts);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,407 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Factory.one;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.jooq.Attachable;
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.SortField;
|
||||
import org.jooq.WindowIgnoreNullsStep;
|
||||
import org.jooq.WindowPartitionByStep;
|
||||
import org.jooq.WindowRowsAndStep;
|
||||
import org.jooq.WindowRowsStep;
|
||||
|
||||
/**
|
||||
* Implementation object for window function DSL API
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class WindowFunction<T> extends AbstractField<T>
|
||||
implements
|
||||
|
||||
// Cascading interface implementations for window function behaviour
|
||||
WindowIgnoreNullsStep<T>,
|
||||
WindowPartitionByStep<T>,
|
||||
WindowRowsStep<T>,
|
||||
WindowRowsAndStep<T>
|
||||
{
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = 5505202722420252635L;
|
||||
|
||||
private final Term term;
|
||||
|
||||
private final QueryPartList<?> arguments;
|
||||
private final SortFieldList withinGroupOrderBy;
|
||||
private final FieldList partitionBy;
|
||||
private final SortFieldList orderBy;
|
||||
|
||||
private boolean partitionByOne;
|
||||
private boolean ignoreNulls;
|
||||
private boolean respectNulls;
|
||||
private Integer rowsStart;
|
||||
private Integer rowsEnd;
|
||||
|
||||
WindowFunction(String name, DataType<T> type, QueryPart... arguments) {
|
||||
this(name, type, new SortFieldList(), arguments);
|
||||
}
|
||||
|
||||
WindowFunction(Term term, DataType<T> type, QueryPart... arguments) {
|
||||
this(term, type, new SortFieldList(), arguments);
|
||||
}
|
||||
|
||||
WindowFunction(String name, DataType<T> type, SortFieldList withinGroupOrderBy, QueryPart... arguments) {
|
||||
super(name, type);
|
||||
|
||||
this.partitionBy = new FieldList();
|
||||
this.orderBy = new SortFieldList();
|
||||
this.arguments = new QueryPartList<QueryPart>(Arrays.asList(arguments));
|
||||
this.term = null;
|
||||
this.withinGroupOrderBy = withinGroupOrderBy;
|
||||
}
|
||||
|
||||
WindowFunction(Term term, DataType<T> type, SortFieldList withinGroupOrderBy, QueryPart... arguments) {
|
||||
super(term.name().toLowerCase(), type);
|
||||
|
||||
this.partitionBy = new FieldList();
|
||||
this.orderBy = new SortFieldList();
|
||||
this.arguments = new QueryPartList<QueryPart>(Arrays.asList(arguments));
|
||||
this.term = term;
|
||||
this.withinGroupOrderBy = withinGroupOrderBy;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Field API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final List<Attachable> getAttachables() {
|
||||
return getAttachables(arguments, partitionBy, orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext context) {
|
||||
context.keyword(getFNName(context.getDialect()));
|
||||
context.sql("(");
|
||||
|
||||
if (!arguments.isEmpty()) {
|
||||
context.sql(arguments);
|
||||
}
|
||||
|
||||
if (ignoreNulls) {
|
||||
if (context.getDialect() == SQLDialect.DB2) {
|
||||
context.sql(", 'IGNORE NULLS'");
|
||||
}
|
||||
else {
|
||||
context.keyword(" ignore nulls");
|
||||
}
|
||||
}
|
||||
else if (respectNulls) {
|
||||
if (context.getDialect() == SQLDialect.DB2) {
|
||||
context.sql(", 'RESPECT NULLS'");
|
||||
}
|
||||
else {
|
||||
context.keyword(" respect nulls");
|
||||
}
|
||||
}
|
||||
|
||||
context.sql(")");
|
||||
if (!withinGroupOrderBy.isEmpty()) {
|
||||
context.keyword(" within group (order by ")
|
||||
.sql(withinGroupOrderBy)
|
||||
.sql(")");
|
||||
}
|
||||
|
||||
String glue = "";
|
||||
context.keyword(" over (");
|
||||
if (!partitionBy.isEmpty()) {
|
||||
if (partitionByOne && context.getDialect() == SQLDialect.SYBASE) {
|
||||
// Ignore partition clause. Sybase does not support this construct
|
||||
}
|
||||
else {
|
||||
context.sql(glue)
|
||||
.keyword("partition by ")
|
||||
.sql(partitionBy);
|
||||
|
||||
glue = " ";
|
||||
}
|
||||
}
|
||||
|
||||
if (!orderBy.isEmpty()) {
|
||||
context.sql(glue)
|
||||
.keyword("order by ");
|
||||
|
||||
switch (context.getDialect()) {
|
||||
|
||||
// SQL Server and Sybase don't allow for fully qualified fields
|
||||
// in the ORDER BY clause of an analytic expression
|
||||
case SQLSERVER: // No break
|
||||
case SYBASE: {
|
||||
for (SortField<?> f : orderBy) {
|
||||
SortFieldImpl<?> field = (SortFieldImpl<?>) f;
|
||||
field.toSQLInAnalyticClause(context);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
context.sql(orderBy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glue = " ";
|
||||
}
|
||||
|
||||
if (rowsStart != null) {
|
||||
context.sql(glue);
|
||||
context.keyword("rows ");
|
||||
|
||||
if (rowsEnd != null) {
|
||||
context.keyword("between ");
|
||||
toSQLRows(context, rowsStart);
|
||||
|
||||
context.keyword(" and ");
|
||||
toSQLRows(context, rowsEnd);
|
||||
}
|
||||
else {
|
||||
toSQLRows(context, rowsStart);
|
||||
}
|
||||
|
||||
glue = " ";
|
||||
}
|
||||
|
||||
context.sql(")");
|
||||
}
|
||||
|
||||
private final String getFNName(SQLDialect dialect) {
|
||||
if (term != null) {
|
||||
return term.translate(dialect);
|
||||
}
|
||||
else {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
private final void toSQLRows(RenderContext context, Integer rows) {
|
||||
if (rows == Integer.MIN_VALUE) {
|
||||
context.keyword("unbounded preceding");
|
||||
}
|
||||
else if (rows == Integer.MAX_VALUE) {
|
||||
context.keyword("unbounded following");
|
||||
}
|
||||
else if (rows < 0) {
|
||||
context.sql(-rows);
|
||||
context.keyword(" preceding");
|
||||
}
|
||||
else if (rows > 0) {
|
||||
context.sql(rows);
|
||||
context.keyword(" following");
|
||||
}
|
||||
else {
|
||||
context.keyword("current row");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {
|
||||
context.bind((QueryPart) arguments)
|
||||
.bind((QueryPart) partitionBy)
|
||||
.bind((QueryPart) orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Window function API
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> ignoreNulls() {
|
||||
ignoreNulls = true;
|
||||
respectNulls = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> respectNulls() {
|
||||
ignoreNulls = false;
|
||||
respectNulls = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> over() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> partitionBy(Field<?>... fields) {
|
||||
partitionBy.addAll(Arrays.asList(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> partitionByOne() {
|
||||
partitionByOne = true;
|
||||
partitionBy.add(one());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> orderBy(Field<?>... fields) {
|
||||
orderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> orderBy(SortField<?>... fields) {
|
||||
orderBy.addAll(Arrays.asList(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> orderBy(Collection<SortField<?>> fields) {
|
||||
orderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsUnboundedPreceding() {
|
||||
rowsStart = Integer.MIN_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsPreceding(int number) {
|
||||
rowsStart = -number;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsCurrentRow() {
|
||||
rowsStart = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsUnboundedFollowing() {
|
||||
rowsStart = Integer.MAX_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsFollowing(int number) {
|
||||
rowsStart = number;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsBetweenUnboundedPreceding() {
|
||||
rowsUnboundedPreceding();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsBetweenPreceding(int number) {
|
||||
rowsPreceding(number);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsBetweenCurrentRow() {
|
||||
rowsCurrentRow();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsBetweenUnboundedFollowing() {
|
||||
rowsUnboundedFollowing();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> rowsBetweenFollowing(int number) {
|
||||
rowsFollowing(number);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> andUnboundedPreceding() {
|
||||
rowsEnd = Integer.MIN_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> andPreceding(int number) {
|
||||
rowsEnd = -number;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> andCurrentRow() {
|
||||
rowsEnd = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> andUnboundedFollowing() {
|
||||
rowsEnd = Integer.MAX_VALUE;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowFunction<T> andFollowing(int number) {
|
||||
rowsEnd = number;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user