HHH-15515 make pi a portable HQL function

This commit is contained in:
Gavin King 2022-09-15 22:12:02 +02:00
parent 9804a22db0
commit 1b5935e66d
4 changed files with 97 additions and 71 deletions

View File

@ -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

View File

@ -652,124 +652,126 @@ public abstract class Dialect implements ConversionContext {
* query language specification:
*
* <ul>
* <li> avg(arg) - aggregate function
* <li> count([distinct ]arg) - aggregate function
* <li> max(arg) - aggregate function
* <li> min(arg) - aggregate function
* <li> sum(arg) - aggregate function
* <li> <code>avg(arg)</code> - aggregate function
* <li> <code>count([distinct ]arg)</code> - aggregate function
* <li> <code>max(arg)</code> - aggregate function
* <li> <code>min(arg)</code> - aggregate function
* <li> <code>sum(arg)</code> - aggregate function
* </ul>
*
* <ul>
* <li> coalesce(arg0, arg1, ...)
* <li> nullif(arg0, arg1)
* <li> <code>coalesce(arg0, arg1, ...)</code>
* <li> <code>nullif(arg0, arg1)</code>
* </ul>
*
* <ul>
* <li> lower(arg)
* <li> upper(arg)
* <li> length(arg)
* <li> concat(arg0, arg1, ...)
* <li> locate(pattern, string[, start])
* <li> substring(string, start[, length])
* <li> trim([[spec ][character ]from] string)
* <li> <code>lower(arg)</code>
* <li> <code>upper(arg)</code>
* <li> <code>length(arg)</code>
* <li> <code>concat(arg0, arg1, ...)</code>
* <li> <code>locate(pattern, string[, start])</code>
* <li> <code>substring(string, start[, length])</code>
* <li> <code>trim([[spec ][character ]from] string)</code>
* </ul>
*
* <ul>
* <li> abs(arg)
* <li> mod(arg0, arg1)
* <li> sqrt(arg)
* <li> <code>abs(arg)</code>
* <li> <code>mod(arg0, arg1)</code>
* <li> <code>sqrt(arg)</code>
* </ul>
*
* <ul>
* <li> current date
* <li> current time
* <li> current timestamp
* <li> <code>current date</code>
* <li> <code>current time</code>
* <li> <code>current timestamp</code>
* </ul>
*
* Along with an additional set of functions defined by ANSI SQL:
*
* <ul>
* <li> any(arg) - aggregate function
* <li> every(arg) - aggregate function
* <li> <code>any(arg)</code> - aggregate function
* <li> <code>every(arg)</code> - aggregate function
* </ul>
*
* <ul>
* <li> cast(arg as Type)
* <li> extract(field from arg)
* <li> <code>cast(arg as Type)</code>
* <li> <code>extract(field from arg)</code>
* </ul>
*
* <ul>
* <li> ln(arg)
* <li> exp(arg)
* <li> power(arg0, arg1)
* <li> floor(arg)
* <li> ceiling(arg)
* <li> <code>ln(arg)</code>
* <li> <code>exp(arg)</code>
* <li> <code>power(arg0, arg1)</code>
* <li> <code>floor(arg)</code>
* <li> <code>ceiling(arg)</code>
* </ul>
*
* <ul>
* <li> position(pattern in string)
* <li> substring(string from start[ for length])
* <li> overlay(string placing replacement from start[ for length])
* <li> <code>position(pattern in string)</code>
* <li> <code>substring(string from start[ for length])</code>
* <li> <code>overlay(string placing replacement from start[ for length])</code>
* </ul>
*
* And the following functions for working with java.time types:
* And the following functions for working with <code>java.time</code>
* types:
*
* <ul>
* <li> local date
* <li> local time
* <li> local datetime
* <li> offset datetime
* <li> instant
* <li> <code>local date</code>
* <li> <code>local time</code>
* <li> <code>local datetime</code>
* <li> <code>offset datetime</code>
* <li> <code>instant</code>
* </ul>
*
* And a number of additional "standard" functions:
*
* <ul>
* <li> left(string, length)
* <li> right(string, length)
* <li> replace(string, pattern, replacement)
* <li> pad(string with length spec[ character])
* <li> <code>left(string, length)</code>
* <li> <code>right(string, length)</code>
* <li> <code>replace(string, pattern, replacement)</code>
* <li> <code>pad(string with length spec[ character])</code>
* </ul>
*
* <ul>
* <li> log10(arg)
* <li> sign(arg)
* <li> sin(arg)
* <li> cos(arg)
* <li> tan(arg)
* <li> asin(arg)
* <li> acos(arg)
* <li> atan(arg)
* <li> atan2(arg0, arg1)
* <li> round(arg0, arg1)
* <li> least(arg0, arg1, ...)
* <li> greatest(arg0, arg1, ...)
* <li> <code>pi</code>
* <li> <code>log10(arg)</code>
* <li> <code>sign(arg)</code>
* <li> <code>sin(arg)</code>
* <li> <code>cos(arg)</code>
* <li> <code>tan(arg)</code>
* <li> <code>asin(arg)</code>
* <li> <code>acos(arg)</code>
* <li> <code>atan(arg)</code>
* <li> <code>atan2(arg0, arg1)</code>
* <li> <code>round(arg0, arg1)</code>
* <li> <code>least(arg0, arg1, ...)</code>
* <li> <code>greatest(arg0, arg1, ...)</code>
* </ul>
*
* <ul>
* <li> format(datetime as pattern)
* <li> collate(string as collation)
* <li> str(arg) - synonym of cast(a as String)
* <li> ifnull(arg0, arg1) - synonym of coalesce(a, b)
* <li> <code>format(datetime as pattern)</code>
* <li> <code>collate(string as collation)</code>
* <li> <code>str(arg)</code> - synonym of <code>cast(a as String)</code>
* <li> <code>ifnull(arg0, arg1)</code> - synonym of <code>coalesce(a, b)</code>
* </ul>
*
* Finally, the following functions are defined as abbreviations
* for extract(), and desugared by the parser:
* Finally, the following functions are defined as abbreviations for
* <code>extract()</code>, and desugared by the parser:
*
* <ul>
* <li> second(arg) - synonym of extract(second from a)
* <li> minute(arg) - synonym of extract(minute from a)
* <li> hour(arg) - synonym of extract(hour from a)
* <li> day(arg) - synonym of extract(day from a)
* <li> month(arg) - synonym of extract(month from a)
* <li> year(arg) - synonym of extract(year from a)
* <li> <code>second(arg)</code> - synonym of <code>extract(second from a)</code>
* <li> <code>minute(arg)</code> - synonym of <code>extract(minute from a)</code>
* <li> <code>hour(arg)</code> - synonym of <code>extract(hour from a)</code>
* <li> <code>day(arg)</code> - synonym of <code>extract(day from a)</code>
* <li> <code>month(arg)</code> - synonym of <code>extract(month from a)</code>
* <li> <code>year(arg)</code> - synonym of <code>extract(year from a)</code>
* </ul>
*
* 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 <code>second()</code>
* 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

View File

@ -388,6 +388,13 @@ public class CommonFunctionFactory {
.register();
}
public void pi_acos() {
functionRegistry.patternDescriptorBuilder( "pi", "acos(-1)" )
.setInvariantType(doubleType)
.setExactArgumentCount(0)
.register();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// character functions

View File

@ -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 )
);
}
);
}
}