From 496aa5ee1ddbac31fb63c38485afc82e91c96e22 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 31 Oct 2011 17:39:05 +0000 Subject: [PATCH] [#893] Simulate ROLLUP function for MySQL, using the WITH ROLLUP modifier --- .../src/org/jooq/test/jOOQAbstractTest.java | 78 +++++++++---- jOOQ/src/main/java/org/jooq/impl/Factory.java | 3 +- jOOQ/src/main/java/org/jooq/impl/Rollup.java | 107 ++++++++++++++++++ 3 files changed, 162 insertions(+), 26 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/impl/Rollup.java diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index a4fd8f9511..ed62d5707a 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -44,6 +44,7 @@ import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import static org.jooq.SQLDialect.ASE; import static org.jooq.SQLDialect.DB2; +import static org.jooq.SQLDialect.MYSQL; import static org.jooq.SQLDialect.SQLSERVER; import static org.jooq.SQLDialect.SYBASE; import static org.jooq.impl.Factory.cast; @@ -2985,7 +2986,6 @@ public abstract class jOOQAbstractTest< case H2: case HSQLDB: case INGRES: - case MYSQL: case POSTGRES: case SQLITE: log.info("SKIPPING", "Group by CUBE / ROLLUP tests"); @@ -2993,11 +2993,62 @@ public abstract class jOOQAbstractTest< } Result result; - Field groupingId = groupingId(TBook_ID(), TBook_AUTHOR_ID()); + // Simple ROLLUP clause + // -------------------- + result = create().select( + TBook_ID(), + TBook_AUTHOR_ID()) + .from(TBook()) + .groupBy(rollup( + TBook_ID(), + TBook_AUTHOR_ID())) + .fetch(); + + System.out.println(result.format()); + assertEquals(9, result.size()); + + if (getDialect() == DB2) { + assertEquals(Arrays.asList(null, 1, 2, 3, 4, 1, 2, 3, 4), result.getValues(0)); + assertEquals(Arrays.asList(null, null, null, null, null, 1, 1, 2, 2), result.getValues(1)); + } + else { + assertEquals(Arrays.asList(1, 1, 2, 2, 3, 3, 4, 4, null), result.getValues(0)); + assertEquals(Arrays.asList(1, null, 1, null, 2, null, 2, null, null), result.getValues(1)); + } + + if (getDialect() == MYSQL) { + log.info("SKIPPING", "CUBE and GROUPING SETS tests"); + return; + } + + // ROLLUP clause + // ------------- + Field groupingId = groupingId(TBook_ID(), TBook_AUTHOR_ID()); if (asList(DB2, SYBASE).contains(getDialect())) groupingId = one(); + result = create().select( + TBook_ID(), + TBook_AUTHOR_ID(), + grouping(TBook_ID()), + groupingId) + .from(TBook()) + .groupBy(rollup( + TBook_ID(), + TBook_AUTHOR_ID())) + .orderBy( + TBook_ID().asc().nullsFirst(), + TBook_AUTHOR_ID().asc().nullsFirst()).fetch(); + + assertEquals(9, result.size()); + assertEquals(Arrays.asList(null, 1, 1, 2, 2, 3, 3, 4, 4), result.getValues(0)); + assertEquals(Arrays.asList(null, null, 1, null, 1, null, 2, null, 2), result.getValues(1)); + assertEquals(Arrays.asList(1, 0, 0, 0, 0, 0, 0, 0, 0), result.getValues(2)); + + if (!asList(DB2, SYBASE).contains(getDialect())) + assertEquals(Arrays.asList(3, 1, 0, 1, 0, 1, 0, 1, 0), result.getValues(3)); + // CUBE clause // ----------- result = create().select( @@ -3021,29 +3072,6 @@ public abstract class jOOQAbstractTest< if (!asList(DB2, SYBASE).contains(getDialect())) assertEquals(Arrays.asList(3, 2, 2, 1, 0, 1, 0, 1, 0, 1, 0), result.getValues(3)); - // ROLLUP clause - // ------------- - result = create().select( - TBook_ID(), - TBook_AUTHOR_ID(), - grouping(TBook_ID()), - groupingId) - .from(TBook()) - .groupBy(rollup( - TBook_ID(), - TBook_AUTHOR_ID())) - .orderBy( - TBook_ID().asc().nullsFirst(), - TBook_AUTHOR_ID().asc().nullsFirst()).fetch(); - - assertEquals(9, result.size()); - assertEquals(Arrays.asList(null, 1, 1, 2, 2, 3, 3, 4, 4), result.getValues(0)); - assertEquals(Arrays.asList(null, null, 1, null, 1, null, 2, null, 2), result.getValues(1)); - assertEquals(Arrays.asList(1, 0, 0, 0, 0, 0, 0, 0, 0), result.getValues(2)); - - if (!asList(DB2, SYBASE).contains(getDialect())) - assertEquals(Arrays.asList(3, 1, 0, 1, 0, 1, 0, 1, 0), result.getValues(3)); - // GROUPING SETS clause // -------------------- result = create().select( diff --git a/jOOQ/src/main/java/org/jooq/impl/Factory.java b/jOOQ/src/main/java/org/jooq/impl/Factory.java index fe0e233730..92a17e0340 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Factory.java +++ b/jOOQ/src/main/java/org/jooq/impl/Factory.java @@ -1765,6 +1765,7 @@ public class Factory implements Configuration { * This has been observed to work with the following databases: *
    *
  • DB2
  • + *
  • MySQL (simulated using the GROUP BY .. WITH ROLLUP clause)
  • *
  • Oracle
  • *
  • SQL Server
  • *
  • Sybase SQL Anywhere
  • @@ -1781,7 +1782,7 @@ public class Factory implements Configuration { * @return A field to be used in a GROUP BY clause */ public static Field rollup(Field... fields) { - return function("rollup", Object.class, fields); + return new Rollup(fields); } /** diff --git a/jOOQ/src/main/java/org/jooq/impl/Rollup.java b/jOOQ/src/main/java/org/jooq/impl/Rollup.java new file mode 100644 index 0000000000..3bc22dedc0 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/Rollup.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2009-2011, 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.function; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; + +import org.jooq.Attachable; +import org.jooq.BindContext; +import org.jooq.Configuration; +import org.jooq.Field; +import org.jooq.RenderContext; + +/** + * @author Lukas Eder + */ +class Rollup extends AbstractFunction { + + /** + * Generated UID + */ + private static final long serialVersionUID = -5820608758939548704L; + + Rollup(Field... fields) { + super("rollup", SQLDataType.OTHER, fields); + } + + @Override + final Field getFunction0(Configuration configuration) { + switch (configuration.getDialect()) { + case MYSQL: + return new WithRollup(); + + default: + return function("rollup", Object.class, getArguments()); + } + } + + private class WithRollup extends AbstractField { + + /** + * Generated UID + */ + private static final long serialVersionUID = -1298546875559286735L; + + WithRollup() { + super("rollup", SQLDataType.OTHER); + } + + @Override + public final List getAttachables() { + return Rollup.this.getAttachables(); + } + + @Override + public final void toSQL(RenderContext context) { + context.sql(new FieldList(Arrays.asList(getArguments()))) + .sql(" with rollup"); + } + + @Override + public final void bind(BindContext context) throws SQLException { + context.bind(getArguments()); + } + + @Override + public final boolean isNullLiteral() { + return false; + } + } +}