diff --git a/jOOQ-meta/src/main/java/org/jooq/util/hsqldb/HSQLDBDatabase.java b/jOOQ-meta/src/main/java/org/jooq/util/hsqldb/HSQLDBDatabase.java index 35a5cfe83a..d7ff602acc 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/hsqldb/HSQLDBDatabase.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/hsqldb/HSQLDBDatabase.java @@ -41,6 +41,7 @@ package org.jooq.util.hsqldb; +import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.nvl; import static org.jooq.util.hsqldb.information_schema.Tables.CHECK_CONSTRAINTS; import static org.jooq.util.hsqldb.information_schema.Tables.ELEMENT_TYPES; @@ -316,7 +317,8 @@ public class HSQLDBDatabase extends AbstractDatabase { ROUTINES.SPECIFIC_NAME, nvl(ELEMENT_TYPES.COLLECTION_TYPE_IDENTIFIER, ROUTINES.DATA_TYPE).as("datatype"), ROUTINES.NUMERIC_PRECISION, - ROUTINES.NUMERIC_SCALE) + ROUTINES.NUMERIC_SCALE, + field(ROUTINES.ROUTINE_DEFINITION.likeRegex(".*(?i:(\\w+\\s+)+aggregate\\s+function).*")).as("aggregate")) .from(ROUTINES) .leftOuterJoin(ELEMENT_TYPES) .on(ROUTINES.ROUTINE_SCHEMA.equal(ELEMENT_TYPES.OBJECT_SCHEMA)) @@ -334,7 +336,8 @@ public class HSQLDBDatabase extends AbstractDatabase { record.getValue(ROUTINES.SPECIFIC_NAME), record.getValue("datatype", String.class), record.getValue(ROUTINES.NUMERIC_PRECISION), - record.getValue(ROUTINES.NUMERIC_SCALE))); + record.getValue(ROUTINES.NUMERIC_SCALE), + record.getValue("aggregate", boolean.class))); } return result; diff --git a/jOOQ-meta/src/main/java/org/jooq/util/hsqldb/HSQLDBRoutineDefinition.java b/jOOQ-meta/src/main/java/org/jooq/util/hsqldb/HSQLDBRoutineDefinition.java index 105e971ab7..b094b775f8 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/hsqldb/HSQLDBRoutineDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/hsqldb/HSQLDBRoutineDefinition.java @@ -40,7 +40,9 @@ */ package org.jooq.util.hsqldb; +import static org.jooq.impl.DSL.condition; import static org.jooq.impl.DSL.nvl; +import static org.jooq.impl.DSL.val; import static org.jooq.util.hsqldb.information_schema.Tables.ELEMENT_TYPES; import static org.jooq.util.hsqldb.information_schema.Tables.PARAMETERS; import static org.jooq.util.hsqldb.information_schema.Tables.ROUTINES; @@ -69,7 +71,11 @@ public class HSQLDBRoutineDefinition extends AbstractRoutineDefinition { private final String specificName; // internal name for the function used by HSQLDB public HSQLDBRoutineDefinition(SchemaDefinition schema, String name, String specificName, String dataType, Number precision, Number scale) { - super(schema, null, name, null, null); + this(schema, name, specificName, dataType, precision, scale, false); + } + + public HSQLDBRoutineDefinition(SchemaDefinition schema, String name, String specificName, String dataType, Number precision, Number scale, boolean aggregate) { + super(schema, null, name, null, null, aggregate); if (!StringUtils.isBlank(dataType)) { DataTypeDefinition type = new DefaultDataTypeDefinition( @@ -109,6 +115,10 @@ public class HSQLDBRoutineDefinition extends AbstractRoutineDefinition { .and(PARAMETERS.DTD_IDENTIFIER.equal(ELEMENT_TYPES.COLLECTION_TYPE_IDENTIFIER)) .where(PARAMETERS.SPECIFIC_SCHEMA.equal(getSchema().getName())) .and(PARAMETERS.SPECIFIC_NAME.equal(this.specificName)) + + // [#3015] HSQLDB user-defined AGGREGATE functions have four parameters, but only one + // is relevant to client code + .and(condition(val(!isAggregate())).or(PARAMETERS.ORDINAL_POSITION.eq(1L))) .orderBy(PARAMETERS.ORDINAL_POSITION.asc()).fetch(); for (Record record : result) { diff --git a/jOOQ-test/src/org/jooq/test/BaseTest.java b/jOOQ-test/src/org/jooq/test/BaseTest.java index b770aa8936..afbacbd5e4 100644 --- a/jOOQ-test/src/org/jooq/test/BaseTest.java +++ b/jOOQ-test/src/org/jooq/test/BaseTest.java @@ -59,6 +59,7 @@ import java.util.UUID; import junit.framework.Assert; +import org.jooq.AggregateFunction; // ... import org.jooq.Configuration; import org.jooq.DAO; @@ -667,6 +668,10 @@ public abstract class BaseTest< return delegate.TIdentityPK_VAL(); } + protected AggregateFunction secondMax(Field val) { + return delegate.secondMax(val); + } + protected Field FAuthorExistsField(String authorName) { return delegate.FAuthorExistsField(authorName); } diff --git a/jOOQ-test/src/org/jooq/test/HSQLDBTest.java b/jOOQ-test/src/org/jooq/test/HSQLDBTest.java index da10fab323..e16efdc219 100644 --- a/jOOQ-test/src/org/jooq/test/HSQLDBTest.java +++ b/jOOQ-test/src/org/jooq/test/HSQLDBTest.java @@ -67,6 +67,7 @@ import java.sql.Date; import java.sql.Timestamp; import java.util.UUID; +import org.jooq.AggregateFunction; // ... import org.jooq.DSLContext; import org.jooq.DataType; @@ -651,6 +652,12 @@ public class HSQLDBTest extends jOOQAbstractTest< return T_IDENTITY_PK.VAL; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + protected AggregateFunction secondMax(Field val) { + return Routines.secondMax(val); + } + @Override protected Field FAuthorExistsField(String authorName) { return Routines.fAuthorExists(authorName); diff --git a/jOOQ-test/src/org/jooq/test/OracleTest.java b/jOOQ-test/src/org/jooq/test/OracleTest.java index 6f5ad84ba5..497d0caac6 100644 --- a/jOOQ-test/src/org/jooq/test/OracleTest.java +++ b/jOOQ-test/src/org/jooq/test/OracleTest.java @@ -62,7 +62,6 @@ xxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -xxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx @@ -110,6 +109,7 @@ xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxxxxxxxxxxx xxxxxx xxxxxxxxxxxxxxx +xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxxxxxxxxx xxxxxx xxxxxxxxxxxxxxxxxxxx @@ -740,6 +740,12 @@ xxxxxx xxxxx xxxxxxxxxx xxxxxxx xxxxxxxxxxxxxxxxx xxxxxx xxxxx x + xxxxxxxxxxxxxxxxxxx xxxxxxxxxxx xxxxxxxxxxx xx + xxxxxxxxx + xxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx xxxx x + xxxxxx xxxxxxxxxxxxxxxxxxxxxxxx + x + xxxxxxxxx xxxxxxxxx xxxxxxx xxxxxxx xxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxx x xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx @@ -1375,42 +1381,6 @@ xxxxxx xxxxx xxxxxxxxxx xxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx x - xxxxx - xxxxxx xxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxxxxx x - - xx xxxxx xxx xxxxxxxxxxx xx xxx xxxxxxxxx xxxxxxxx - xxxxxxxxxxxxx xxxxxxx x - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - xxxxxxxxxxxxxx - xxxxxxxxxxxxxxxxxxxxxxxxxxx - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - xxxxxxxxx xxxxxxxxxxxxxxx - - xxxxxxxxxxxxxxxxxxxxxx xxx xxxxxxxxx - - xx xxxxx xxx xxxxxxxxxxx xx xxx xxxxxxxxxx xxxxxxxx - xxxxxxxxxxxxx xxxxxxx x - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - xxxxxxxxxxxxxx - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - xxxxxxxxx xxxxxxxxxxxxxxx - - xxxxxxxxxxxxxxxxxxxxxx xx xx xxx xxxxxxxxx - - xx xxxxxxx xxxxx xx xxxxx xxxxxxxxxx xxx xxxxxxxxx xxxxxxxx xxxxxx xxx - xxxxxxxxxx xxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx - - xxxxxxxxxxxxx xxxxxxx x - xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - xxxxxxxxxxxxxx - xxxxxxxxxxxxxxxxxxxxxxxxxxx - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - xxxxxxxxx xxxxxxxxxxxxxxx - - xxxxxxxxxxxxxxxxxxxxxx xxx xxxxxxxxx - - x - xxxxx xxxxxx xxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxxxxx x xxxxxxxxxx xxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/AggregateWindowFunctionTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/AggregateWindowFunctionTests.java index 66a279a95c..1bd5ad0e8e 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/AggregateWindowFunctionTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/AggregateWindowFunctionTests.java @@ -106,6 +106,7 @@ import java.sql.Date; import java.util.Arrays; import java.util.List; +import org.jooq.DSLContext; import org.jooq.Field; import org.jooq.Name; import org.jooq.Record; @@ -122,6 +123,7 @@ import org.jooq.TableRecord; import org.jooq.UpdatableRecord; import org.jooq.WindowDefinition; import org.jooq.WindowSpecification; +import org.jooq.impl.DSL; import org.jooq.test.BaseTest; import org.jooq.test.jOOQAbstractTest; @@ -161,17 +163,63 @@ extends BaseTest median = median(TBook_ID()); + // Check the correctness of the aggregate function + List result1 = + create().select(secondMax(TBook_ID())) + .from(TBook()) + .groupBy(TBook_AUTHOR_ID()) + .orderBy(TBook_AUTHOR_ID().asc()) + .fetch(0, Integer.class); - // Some dialects don't support a median function or a simulation thereof - // Use AVG instead, as in this example the values of MEDIAN and AVG - // are the same - switch (dialect().family()) { - /* [pro] xx + assertEquals(asList(1, 3), result1); + + /* [pro] xx + xxxxxx xxxxxxxxxxxxxxxxxxxx x + xxxx xxxxxxx x + xx xxxxx xxx xxxxxxxxxxx xx xxx xxxxxxxxxx xxxxxxxx + xxxxxxxxxxxxx xxxxxxx x + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxx xxxxxxxxxxxxxxx + + xxxxxxxxxxxxxxxxxxxxxx xx xx xxx xxxxxxxxx + + xx xxxxxxx xxxxx xx xxxxx xxxxxxxxxx xxx xxxxxxxxx xxxxxxxx xxxxxx xxx + xxxxxxxxxx xxxxxx x xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx + + xxxxxxxxxxxxx xxxxxxx x + xxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxx xxxxxxxxxxxxxxx + + xxxxxxxxxxxxxxxxxxxxxx xxx xxxxxxxxx + xxxxxx + x + x + xx xxxxx xx + x + + xxxxx + xxxxxx xxxx xxxxxxxxxxxxxxxxxxxxxxxx xxxxxx xxxxxxxxx x + + xx xxxxxxxx xxxxxxxxx xxxxxxxxxx xxxxxxxxx xx xxx xxxxxxxxx + xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + xxxxxxxxxxxxxxxxx xxxxxx x xxxxxxxxxxxxxxxxxxx + + xx xxxx xxxxxxxx xxxxx xxxxxxx x xxxxxx xxxxxxxx xx x xxxxxxxxxx xxxxxxx + xx xxx xxx xxxxxxxx xx xx xxxx xxxxxxx xxx xxxxxx xx xxxxxx xxx xxx + xx xxx xxx xxxx + xxxxxx xxxxxxxxxxxxxxxxxxxx x + xx xxxxx xx xxxx xxxx xxxx xxxxxxx xxxx xxxx diff --git a/jOOQ-test/src/org/jooq/test/hsqldb/create.sql b/jOOQ-test/src/org/jooq/test/hsqldb/create.sql index 9876b6d11a..0b75a8ded9 100644 --- a/jOOQ-test/src/org/jooq/test/hsqldb/create.sql +++ b/jOOQ-test/src/org/jooq/test/hsqldb/create.sql @@ -22,6 +22,7 @@ DROP FUNCTION IF EXISTS f2502_2/ DROP PROCEDURE IF EXISTS p2502/ DROP FUNCTION IF EXISTS f2515/ DROP FUNCTION IF EXISTS f2515_/ +DROP FUNCTION IF EXISTS second_max/ DROP VIEW IF EXISTS v_author/ DROP VIEW IF EXISTS v_book/ @@ -541,3 +542,27 @@ BEGIN ATOMIC SET io2 = i2; END / + +CREATE AGGREGATE FUNCTION second_max( + IN val INTEGER, + IN flag BOOLEAN, + INOUT highest INTEGER, + INOUT second_highest INTEGER +) +RETURNS INTEGER +CONTAINS SQL +BEGIN ATOMIC + DECLARE temp INTEGER; + + IF flag THEN + RETURN second_highest; + ELSE + SET temp = highest; + SET highest = GREATEST(COALESCE(highest, -2147483648), val); + SET second_highest = CASE WHEN temp < highest THEN temp ELSE second_highest END; + + SET temp = GREATEST(COALESCE(second_highest, -2147483648), val); + SET second_highest = CASE WHEN temp < highest THEN temp ELSE second_highest END; + END IF; +END +/ diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index 29e3c082e1..57d16116cb 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -72,6 +72,7 @@ import java.util.Map; import java.util.Properties; import java.util.UUID; +import org.jooq.AggregateFunction; // ... import org.jooq.DAO; import org.jooq.DSLContext; @@ -915,6 +916,9 @@ public abstract class jOOQAbstractTest< protected abstract TableField TIdentityPK_ID(); protected abstract TableField TIdentityPK_VAL(); + protected AggregateFunction secondMax(Field val) { + return null; + } protected abstract Field FAuthorExistsField(String authorName); protected abstract Field FOneField(); protected abstract Field FNumberField(Number n); @@ -2081,6 +2085,11 @@ public abstract class jOOQAbstractTest< new FunctionTests(this).testBitwiseOperations(); } + @Test + public void testUserDefinedAggregateFunctions() throws Exception { + new AggregateWindowFunctionTests(this).testUserDefinedAggregateFunctions(); + } + @Test public void testAggregateFunctions() throws Exception { new AggregateWindowFunctionTests(this).testAggregateFunctions();