[#1274] Add support for the Oracle LISTAGG() analytic function
This commit is contained in:
parent
fe58db50d5
commit
490ca642bf
@ -50,6 +50,7 @@ import static org.jooq.impl.Factory.denseRank;
|
||||
import static org.jooq.impl.Factory.firstValue;
|
||||
import static org.jooq.impl.Factory.lag;
|
||||
import static org.jooq.impl.Factory.lead;
|
||||
import static org.jooq.impl.Factory.listAgg;
|
||||
import static org.jooq.impl.Factory.max;
|
||||
import static org.jooq.impl.Factory.maxDistinct;
|
||||
import static org.jooq.impl.Factory.median;
|
||||
@ -727,4 +728,62 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListAgg() throws Exception {
|
||||
switch (getDialect()) {
|
||||
case ASE:
|
||||
case CUBRID:
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
case INGRES:
|
||||
case MYSQL:
|
||||
case POSTGRES:
|
||||
case SQLITE:
|
||||
case SQLSERVER:
|
||||
case SYBASE:
|
||||
log.info("SKIPPING", "LISTAGG tests");
|
||||
return;
|
||||
}
|
||||
|
||||
Result<?> result1 = create().select(
|
||||
TAuthor_FIRST_NAME(),
|
||||
TAuthor_LAST_NAME(),
|
||||
listAgg(TBook_TITLE(), ", ").withinGroupOrderBy(TBook_ID().desc()).as("books"))
|
||||
.from(TAuthor())
|
||||
.join(TBook()).on(TAuthor_ID().equal(TBook_AUTHOR_ID()))
|
||||
.groupBy(
|
||||
TAuthor_ID(),
|
||||
TAuthor_FIRST_NAME(),
|
||||
TAuthor_LAST_NAME())
|
||||
.orderBy(TAuthor_ID())
|
||||
.fetch();
|
||||
|
||||
assertEquals(2, result1.size());
|
||||
assertEquals(AUTHOR_FIRST_NAMES, result1.getValues(TAuthor_FIRST_NAME()));
|
||||
assertEquals(AUTHOR_LAST_NAMES, result1.getValues(TAuthor_LAST_NAME()));
|
||||
assertEquals("Animal Farm, 1984", result1.getValue(0, "books"));
|
||||
assertEquals("Brida, O Alquimista", result1.getValue(1, "books"));
|
||||
|
||||
Result<?> result2 = create().select(
|
||||
TAuthor_FIRST_NAME(),
|
||||
TAuthor_LAST_NAME(),
|
||||
listAgg(TBook_TITLE())
|
||||
.withinGroupOrderBy(TBook_ID().asc())
|
||||
.over().partitionBy(TAuthor_ID()))
|
||||
.from(TAuthor())
|
||||
.join(TBook()).on(TAuthor_ID().equal(TBook_AUTHOR_ID()))
|
||||
.orderBy(TBook_ID())
|
||||
.fetch();
|
||||
|
||||
assertEquals(4, result2.size());
|
||||
assertEquals(BOOK_FIRST_NAMES, result2.getValues(TAuthor_FIRST_NAME()));
|
||||
assertEquals(BOOK_LAST_NAMES, result2.getValues(TAuthor_LAST_NAME()));
|
||||
assertEquals("1984Animal Farm", result2.getValue(0, 2));
|
||||
assertEquals("1984Animal Farm", result2.getValue(1, 2));
|
||||
assertEquals("O AlquimistaBrida", result2.getValue(2, 2));
|
||||
assertEquals("O AlquimistaBrida", result2.getValue(3, 2));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1242,6 +1242,11 @@ public abstract class jOOQAbstractTest<
|
||||
new AggregateWindowFunctionTests(this).testAggregateFunctions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListAgg() throws Exception {
|
||||
new AggregateWindowFunctionTests(this).testListAgg();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoredFunctions() throws Exception {
|
||||
new RoutineAndUDTTests(this).testStoredFunctions();
|
||||
|
||||
87
jOOQ/src/main/java/org/jooq/OrderedAggregateFunction.java
Normal file
87
jOOQ/src/main/java/org/jooq/OrderedAggregateFunction.java
Normal file
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import static org.jooq.SQLDialect.ORACLE;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* An ordered aggregate function.
|
||||
* <p>
|
||||
* An ordered aggregate function is an aggregate function with a mandatory
|
||||
* Oracle-specific <code>WITHIN GROUP (ORDER BY ..)</code> clause. An example is
|
||||
* <code>LISTAGG</code>: <code><pre>
|
||||
* SELECT LISTAGG(TITLE, ', ')
|
||||
* WITHIN GROUP (ORDER BY TITLE)
|
||||
* FROM T_BOOK
|
||||
* GROUP BY AUTHOR_ID
|
||||
* </pre></code> The above function groups books by author and aggregates titles
|
||||
* into a concatenated string.
|
||||
* <p>
|
||||
* Ordered aggregate functions can be further converted into window functions
|
||||
* using the <code>OVER(PARTITION BY ..)</code> clause. For example: <code><pre>
|
||||
* SELECT LISTAGG(TITLE, ', ')
|
||||
* WITHIN GROUP (ORDER BY TITLE)
|
||||
* OVER (PARTITION BY AUTHOR_ID)
|
||||
* FROM T_BOOK
|
||||
* </pre></code>
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public interface OrderedAggregateFunction<T> {
|
||||
|
||||
/**
|
||||
* Add an <code>WITHIN GROUP (ORDER BY ..)</code> clause to the ordered
|
||||
* aggregate function
|
||||
*/
|
||||
@Support(ORACLE)
|
||||
AggregateFunction<T> withinGroupOrderBy(Field<?>... fields);
|
||||
|
||||
/**
|
||||
* Add an <code>WITHIN GROUP (ORDER BY ..)</code> clause to the ordered
|
||||
* aggregate function
|
||||
*/
|
||||
@Support
|
||||
AggregateFunction<T> withinGroupOrderBy(SortField<?>... fields);
|
||||
|
||||
/**
|
||||
* Add an <code>WITHIN GROUP (ORDER BY ..)</code> clause to the ordered
|
||||
* aggregate function
|
||||
*/
|
||||
@Support(ORACLE)
|
||||
AggregateFunction<T> withinGroupOrderBy(Collection<SortField<?>> fields);
|
||||
}
|
||||
@ -35,20 +35,26 @@
|
||||
*/
|
||||
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 AggregateFunction<T> {
|
||||
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 boolean distinct;
|
||||
private final SortFieldList withinGroupOrderBy;
|
||||
|
||||
AggregateFunctionImpl(String name, DataType<T> type, Field<?>... arguments) {
|
||||
this(name, false, type, arguments);
|
||||
@ -62,21 +68,41 @@ class AggregateFunctionImpl<T> extends Function<T> implements AggregateFunction<
|
||||
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(), getArguments());
|
||||
return new WindowFunction<T>(getTerm(), getDataType(), withinGroupOrderBy, getArguments());
|
||||
}
|
||||
else {
|
||||
return new WindowFunction<T>(getName(), getDataType(), getArguments());
|
||||
return new WindowFunction<T>(getName(), getDataType(), withinGroupOrderBy, getArguments());
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,4 +114,13 @@ class AggregateFunctionImpl<T> extends Function<T> implements AggregateFunction<
|
||||
|
||||
super.toSQLField(context, field);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void toSQLSuffix(RenderContext context) {
|
||||
if (!withinGroupOrderBy.isEmpty()) {
|
||||
context.keyword(" within group (order by ")
|
||||
.sql(withinGroupOrderBy)
|
||||
.sql(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,6 +100,7 @@ import org.jooq.InsertSetStep;
|
||||
import org.jooq.InsertValuesStep;
|
||||
import org.jooq.LoaderOptionsStep;
|
||||
import org.jooq.MergeUsingStep;
|
||||
import org.jooq.OrderedAggregateFunction;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.QueryPart;
|
||||
@ -4153,6 +4154,22 @@ public class Factory implements FactoryOperations {
|
||||
return new AggregateFunctionImpl<BigDecimal>(Term.VAR_SAMP, SQLDataType.NUMERIC, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the aggregated concatenation for a field.
|
||||
*/
|
||||
@Support(ORACLE)
|
||||
public static OrderedAggregateFunction<String> listAgg(Field<?> field) {
|
||||
return new AggregateFunctionImpl<String>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the aggregated concatenation for a field.
|
||||
*/
|
||||
@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("'", "''") + "'"));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Window functions
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -91,6 +91,7 @@ class Function<T> extends AbstractField<T> {
|
||||
|
||||
context.sql(getArgumentListDelimiter(context, ")"));
|
||||
context.sql(getFNSuffix());
|
||||
toSQLSuffix(context);
|
||||
}
|
||||
|
||||
private final String getFNName(SQLDialect dialect) {
|
||||
@ -159,6 +160,12 @@ class Function<T> extends AbstractField<T> {
|
||||
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);
|
||||
|
||||
@ -45,128 +45,149 @@ import org.jooq.SQLDialect;
|
||||
*/
|
||||
enum Term {
|
||||
|
||||
ATAN2,
|
||||
BIT_LENGTH,
|
||||
CHAR_LENGTH,
|
||||
OCTET_LENGTH,
|
||||
STDDEV_POP,
|
||||
STDDEV_SAMP,
|
||||
VAR_POP,
|
||||
VAR_SAMP
|
||||
ATAN2 {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect) {
|
||||
case ASE:
|
||||
case SQLSERVER:
|
||||
return "atn2";
|
||||
}
|
||||
|
||||
return "atan2";
|
||||
}
|
||||
},
|
||||
BIT_LENGTH {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect) {
|
||||
case ASE:
|
||||
return "8 * datalength";
|
||||
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case INGRES:
|
||||
case SQLITE:
|
||||
case SYBASE:
|
||||
return "8 * length";
|
||||
|
||||
case SQLSERVER:
|
||||
return "8 * len";
|
||||
|
||||
case ORACLE:
|
||||
return "8 * lengthb";
|
||||
}
|
||||
|
||||
return "bit_length";
|
||||
}
|
||||
},
|
||||
CHAR_LENGTH {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case INGRES:
|
||||
case ORACLE:
|
||||
case SQLITE:
|
||||
case SYBASE:
|
||||
return "length";
|
||||
|
||||
case SQLSERVER:
|
||||
return "len";
|
||||
}
|
||||
|
||||
return "char_length";
|
||||
}
|
||||
},
|
||||
LIST_AGG {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
return "listagg";
|
||||
}
|
||||
},
|
||||
OCTET_LENGTH {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case INGRES:
|
||||
case SQLITE:
|
||||
case SYBASE:
|
||||
return "length";
|
||||
|
||||
case SQLSERVER:
|
||||
return "len";
|
||||
|
||||
case ORACLE:
|
||||
return "lengthb";
|
||||
}
|
||||
|
||||
return "octet_length";
|
||||
}
|
||||
},
|
||||
STDDEV_POP {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
return "stddev";
|
||||
|
||||
case SQLSERVER:
|
||||
return "stdevp";
|
||||
}
|
||||
|
||||
return "stddev_pop";
|
||||
}
|
||||
},
|
||||
STDDEV_SAMP {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
return "stddev";
|
||||
|
||||
case SQLSERVER:
|
||||
return "stdev";
|
||||
}
|
||||
|
||||
return "stddev_samp";
|
||||
}
|
||||
},
|
||||
VAR_POP {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
return "variance";
|
||||
|
||||
case SQLSERVER:
|
||||
return "varp";
|
||||
}
|
||||
|
||||
return "var_pop";
|
||||
}
|
||||
},
|
||||
VAR_SAMP {
|
||||
@Override
|
||||
public String translate(SQLDialect dialect) {
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
return "variance";
|
||||
|
||||
case SQLSERVER:
|
||||
return "var";
|
||||
}
|
||||
|
||||
return "var_samp";
|
||||
}
|
||||
},
|
||||
|
||||
;
|
||||
|
||||
public final String translate(SQLDialect dialect) {
|
||||
switch (this) {
|
||||
case ATAN2:
|
||||
switch (dialect) {
|
||||
case ASE:
|
||||
case SQLSERVER:
|
||||
return "atn2";
|
||||
}
|
||||
|
||||
return "atan2";
|
||||
|
||||
case BIT_LENGTH:
|
||||
switch (dialect) {
|
||||
case ASE:
|
||||
return "8 * datalength";
|
||||
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case INGRES:
|
||||
case SQLITE:
|
||||
case SYBASE:
|
||||
return "8 * length";
|
||||
|
||||
case SQLSERVER:
|
||||
return "8 * len";
|
||||
|
||||
case ORACLE:
|
||||
return "8 * lengthb";
|
||||
}
|
||||
|
||||
return "bit_length";
|
||||
|
||||
case CHAR_LENGTH:
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case INGRES:
|
||||
case ORACLE:
|
||||
case SQLITE:
|
||||
case SYBASE:
|
||||
return "length";
|
||||
|
||||
case SQLSERVER:
|
||||
return "len";
|
||||
}
|
||||
|
||||
return "char_length";
|
||||
|
||||
case OCTET_LENGTH:
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case INGRES:
|
||||
case SQLITE:
|
||||
case SYBASE:
|
||||
return "length";
|
||||
|
||||
case SQLSERVER:
|
||||
return "len";
|
||||
|
||||
case ORACLE:
|
||||
return "lengthb";
|
||||
}
|
||||
|
||||
return "octet_length";
|
||||
|
||||
case STDDEV_POP:
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
return "stddev";
|
||||
|
||||
case SQLSERVER:
|
||||
return "stdevp";
|
||||
}
|
||||
|
||||
return "stddev_pop";
|
||||
|
||||
case STDDEV_SAMP:
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
return "stddev";
|
||||
|
||||
case SQLSERVER:
|
||||
return "stdev";
|
||||
}
|
||||
|
||||
return "stddev_samp";
|
||||
|
||||
case VAR_POP:
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
return "variance";
|
||||
|
||||
case SQLSERVER:
|
||||
return "varp";
|
||||
}
|
||||
|
||||
return "var_pop";
|
||||
|
||||
case VAR_SAMP:
|
||||
switch (dialect) {
|
||||
case DB2:
|
||||
return "variance";
|
||||
|
||||
case SQLSERVER:
|
||||
return "var";
|
||||
}
|
||||
|
||||
return "var_samp";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Translate the term to its dialect-specific variant
|
||||
*/
|
||||
abstract String translate(SQLDialect dialect);
|
||||
}
|
||||
|
||||
@ -77,6 +77,7 @@ implements
|
||||
private final Term term;
|
||||
|
||||
private final QueryPartList<?> arguments;
|
||||
private final SortFieldList withinGroupOrderBy;
|
||||
private final FieldList partitionBy;
|
||||
private final SortFieldList orderBy;
|
||||
|
||||
@ -86,22 +87,32 @@ implements
|
||||
private Integer rowsStart;
|
||||
private Integer rowsEnd;
|
||||
|
||||
public WindowFunction(String name, DataType<T> type, QueryPart... arguments) {
|
||||
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;
|
||||
}
|
||||
|
||||
public WindowFunction(Term term, DataType<T> type, QueryPart... arguments) {
|
||||
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;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -139,11 +150,15 @@ implements
|
||||
}
|
||||
}
|
||||
|
||||
context.keyword(") over (")
|
||||
.formatIndentLockStart();
|
||||
context.sql(")");
|
||||
|
||||
boolean newLine = false;
|
||||
if (!withinGroupOrderBy.isEmpty()) {
|
||||
context.keyword(" within group (order by ")
|
||||
.sql(withinGroupOrderBy)
|
||||
.sql(")");
|
||||
}
|
||||
|
||||
context.keyword(" over (");
|
||||
if (!partitionBy.isEmpty()) {
|
||||
if (partitionByOne && context.getDialect() == SQLDialect.SYBASE) {
|
||||
// Ignore partition clause. Sybase does not support this construct
|
||||
@ -151,16 +166,10 @@ implements
|
||||
else {
|
||||
context.keyword("partition by ")
|
||||
.sql(partitionBy);
|
||||
|
||||
newLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!orderBy.isEmpty()) {
|
||||
if (newLine) {
|
||||
context.formatSeparator();
|
||||
}
|
||||
|
||||
context.keyword("order by ");
|
||||
switch (context.getDialect()) {
|
||||
|
||||
@ -181,24 +190,16 @@ implements
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
newLine = true;
|
||||
}
|
||||
|
||||
if (rowsStart != null) {
|
||||
if (newLine) {
|
||||
context.formatSeparator();
|
||||
}
|
||||
|
||||
context.keyword("rows ");
|
||||
|
||||
if (rowsEnd != null) {
|
||||
context.keyword("between ");
|
||||
toSQLRows(context, rowsStart);
|
||||
|
||||
context.formatSeparator()
|
||||
.keyword("and ");
|
||||
|
||||
context.keyword("and ");
|
||||
toSQLRows(context, rowsEnd);
|
||||
}
|
||||
else {
|
||||
@ -206,8 +207,7 @@ implements
|
||||
}
|
||||
}
|
||||
|
||||
context.sql(")")
|
||||
.formatIndentLockEnd();
|
||||
context.sql(")");
|
||||
}
|
||||
|
||||
private final String getFNName(SQLDialect dialect) {
|
||||
|
||||
@ -54,7 +54,7 @@ public class LoggerListener extends DefaultExecuteListener {
|
||||
if (log.isDebugEnabled()) {
|
||||
if (ctx.query() != null) {
|
||||
log.debug("Executing query", ctx.query().getSQL(true));
|
||||
log.debug("Executing query", ctx.query().getSQL(false));
|
||||
// log.debug("Executing query", ctx.query().getSQL(false));
|
||||
}
|
||||
else if (!StringUtils.isBlank(ctx.sql())) {
|
||||
log.debug("Executing query", ctx.sql());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user