From 1b5935e66dc404587b7f425bdb01c9f1553b2f3c Mon Sep 17 00:00:00 2001 From: Gavin King Date: Thu, 15 Sep 2022 22:12:02 +0200 Subject: [PATCH] HHH-15515 make pi a portable HQL function --- .../chapters/query/hql/QueryLanguage.adoc | 1 + .../java/org/hibernate/dialect/Dialect.java | 148 +++++++++--------- .../function/CommonFunctionFactory.java | 7 + .../test/query/hql/StandardFunctionTests.java | 12 ++ 4 files changed, 97 insertions(+), 71 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc index 697cc918e5..7b0ac71a82 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc @@ -1023,6 +1023,7 @@ Next, functions for working with numeric values: | `power()` | Exponentiation | `power(x,y)` | Universal in SQL dialects | `ln()` | Natural logarithm | `ln(x)` | Very common in SQL dialects | `log10()` | Base-10 logarithm | `log10(x)` | Very common in SQL dialects +| `pi` | π | `pi` | Very common in SQL dialects | `sin()`, `cos()`, `tan()`, `asin()`, `acos()`, `atan()`, `atan2()` | Basic trigonometric functions | `sin(theta)`, `cos(theta)`, `atan2(opposite, adjacent)` | Very common in SQL dialects | `round()` | Numeric rounding | As usual: `round(number, places)` | Very common in SQL dialects | `floor()` | Floor function | `floor(x)` | Universal in SQL dialects diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index 23cbc7f081..25590d2851 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -652,124 +652,126 @@ public abstract class Dialect implements ConversionContext { * query language specification: * * * * * * * * * * * * Along with an additional set of functions defined by ANSI SQL: * * * * * * * * * - * And the following functions for working with java.time types: + * And the following functions for working with java.time + * types: * * * * And a number of additional "standard" functions: * * * * * * * - * Finally, the following functions are defined as abbreviations - * for extract(), and desugared by the parser: + * Finally, the following functions are defined as abbreviations for + * extract(), and desugared by the parser: * * * - * Note that according to this definition, the second() function returns - * a floating point value, contrary to the integer type returned by the - * native function with this name on many databases. Thus, we don't just - * naively map these HQL functions to the native SQL functions with the - * same names. + * Note that according to this definition, the second() + * function returns a floating point value, contrary to the integer + * type returned by the native function with this name on many databases. + * Thus, we don't just naively map these HQL functions to the native SQL + * functions with the same names. */ public void initializeFunctionRegistry(QueryEngine queryEngine) { final TypeConfiguration typeConfiguration = queryEngine.getTypeConfiguration(); @@ -811,6 +813,10 @@ public abstract class Dialect implements ConversionContext { functionFactory.trigonometry(); + //pi supported on most databases, but emulate it here + + functionFactory.pi_acos(); + //coalesce() function, supported by most databases, must be emulated //in terms of nvl() for platforms which don't support it natively diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java index 933aaf3c4e..ca3bd705ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java @@ -388,6 +388,13 @@ public class CommonFunctionFactory { .register(); } + public void pi_acos() { + functionRegistry.patternDescriptorBuilder( "pi", "acos(-1)" ) + .setInvariantType(doubleType) + .setExactArgumentCount(0) + .register(); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // character functions diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/StandardFunctionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/StandardFunctionTests.java index 96040851d7..95b2f9fe80 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/StandardFunctionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/StandardFunctionTests.java @@ -907,4 +907,16 @@ public class StandardFunctionTests { } ); } + + @Test + public void testPi(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + assertThat( + session.createQuery("select pi").getSingleResult(), + is( Math.PI ) + ); + } + ); + } }