[#1273] Simulate GROUP_CONCAT() aggregate function using Oracle's LISTAGG() function, where available

This commit is contained in:
Lukas Eder 2012-04-06 20:40:46 +00:00
parent 003344ef32
commit 7acc26838a
6 changed files with 30 additions and 14 deletions

View File

@ -736,7 +736,6 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
case ASE:
case DERBY:
case INGRES:
case POSTGRES:
case SQLITE:
case SQLSERVER:
log.info("SKIPPING", "LISTAGG tests");
@ -776,6 +775,7 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
case H2:
case HSQLDB:
case MYSQL:
case POSTGRES:
case SYBASE:
log.info("SKIPPING", "LISTAGG window function tests");
return;

View File

@ -41,6 +41,7 @@ import static org.jooq.SQLDialect.H2;
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.MYSQL;
import static org.jooq.SQLDialect.ORACLE;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SYBASE;
import java.util.Collection;
@ -59,18 +60,18 @@ public interface GroupConcatOrderByStep extends GroupConcatSeparatorStep {
/**
* Add an <code>ORDER BY</code> clause to the query
*/
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SYBASE })
GroupConcatSeparatorStep orderBy(Field<?>... fields);
/**
* Add an <code>ORDER BY</code> clause to the query
*/
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SYBASE })
GroupConcatSeparatorStep orderBy(SortField<?>... fields);
/**
* Add an <code>ORDER BY</code> clause to the query
*/
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SYBASE })
GroupConcatSeparatorStep orderBy(Collection<SortField<?>> fields);
}

View File

@ -41,6 +41,7 @@ import static org.jooq.SQLDialect.H2;
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.MYSQL;
import static org.jooq.SQLDialect.ORACLE;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SYBASE;
import org.jooq.impl.Factory;
@ -56,6 +57,6 @@ public interface GroupConcatSeparatorStep extends AggregateFunction<String> {
/**
* Specify the separator on the <code>GROUP_CONCAT</code> function
*/
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SYBASE })
AggregateFunction<String> separator(String separator);
}

View File

@ -4263,7 +4263,7 @@ public class Factory implements FactoryOperations {
*
* @see #groupConcat(Field)
*/
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SYBASE })
public static OrderedAggregateFunction<String> listAgg(Field<?> field) {
return new Function<String>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field));
}
@ -4284,7 +4284,7 @@ public class Factory implements FactoryOperations {
*
* @see #groupConcat(Field, String)
*/
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SYBASE })
public static OrderedAggregateFunction<String> listAgg(Field<?> field, String separator) {
Field<String> literal = literal("'" + separator.replace("'", "''") + "'");
return new Function<String>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field), literal);
@ -4310,7 +4310,7 @@ public class Factory implements FactoryOperations {
*
* @see #listAgg(Field)
*/
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
@Support({ CUBRID, DB2, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SYBASE })
public static GroupConcatOrderByStep groupConcat(Field<?> field) {
return new GroupConcat(nullSafe(field));
}
@ -4333,7 +4333,7 @@ public class Factory implements FactoryOperations {
*
* @see #listAgg(Field)
*/
@Support({ CUBRID, H2, HSQLDB, MYSQL, SYBASE })
@Support({ CUBRID, H2, HSQLDB, MYSQL, POSTGRES, SYBASE })
public static GroupConcatOrderByStep groupConcatDistinct(Field<?> field) {
return new GroupConcat(nullSafe(field), true);
}

View File

@ -42,6 +42,7 @@ import static org.jooq.SQLDialect.DB2;
import static org.jooq.SQLDialect.H2;
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.MYSQL;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SYBASE;
import static org.jooq.impl.Factory.one;
import static org.jooq.impl.Term.LIST_AGG;
@ -172,8 +173,8 @@ class Function<T> extends AbstractField<T> implements
if (term == LIST_AGG && asList(CUBRID, H2, HSQLDB, MYSQL).contains(context.getDialect())) {
toSQLGroupConcat(context);
}
else if (term == LIST_AGG && asList(SYBASE).contains(context.getDialect())) {
toSQLList(context);
else if (term == LIST_AGG && asList(POSTGRES, SYBASE).contains(context.getDialect())) {
toSQLStringAgg(context);
}
else if (term == LIST_AGG && asList(DB2).contains(context.getDialect())) {
toSQLXMLAGG(context);
@ -233,9 +234,9 @@ class Function<T> extends AbstractField<T> implements
}
/**
* [#1275] <code>LIST_AGG</code> simulation for CUBRID, HSQLDB, MySQL
* [#1275] <code>LIST_AGG</code> simulation for Postgres, Sybase
*/
private void toSQLList(RenderContext context) {
private void toSQLStringAgg(RenderContext context) {
context.sql(getFNName(context.getDialect()));
context.sql("(");
@ -243,7 +244,16 @@ class Function<T> extends AbstractField<T> implements
context.keyword("distinct ");
}
context.sql(arguments);
// The explicit cast is needed in Postgres
context.sql(((Field<?>) arguments.get(0)).cast(String.class));
if (arguments.size() > 1) {
context.sql(", ");
context.sql(arguments.get(1));
}
else {
context.sql(", ''");
}
if (!withinGroupOrderBy.isEmpty()) {
context.keyword(" order by ")
@ -251,6 +261,7 @@ class Function<T> extends AbstractField<T> implements
}
context.sql(")");
toSQLOverClause(context);
}
/**

View File

@ -118,6 +118,9 @@ enum Term {
case ORACLE:
return "listagg";
case POSTGRES:
return "string_agg";
case SYBASE:
return "list";
}