-
Notifications
You must be signed in to change notification settings - Fork 3.5k
/
SumReturnTypeResolver.java
139 lines (129 loc) · 4.82 KB
/
SumReturnTypeResolver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.function.Supplier;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.extractArgumentType;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.extractArgumentValuedMapping;
import static org.hibernate.type.SqlTypes.*;
/**
* Resolve according to JPA spec 4.8.5
* <p>
* {@code SUM} returns:
* <ul>
* <li>{@code Long} when applied to state fields of integral types (other than {@code BigInteger});
* <li>{@code Double} when applied to state fields of floating point types;
* <li>{@code BigInteger} when applied to state fields of type {@code BigInteger};
* <li>and {@code BigDecimal} when applied to state fields of type {@code BigDecimal}.
* </ul>
*
* @author Christian Beikov
*/
class SumReturnTypeResolver implements FunctionReturnTypeResolver {
private final BasicType<Long> longType;
private final BasicType<Double> doubleType;
private final BasicType<BigInteger> bigIntegerType;
private final BasicType<BigDecimal> bigDecimalType;
public SumReturnTypeResolver(TypeConfiguration typeConfiguration) {
final BasicType<Long> longType = typeConfiguration.getBasicTypeForJavaType(Long.class);
final BasicType<Double> doubleType = typeConfiguration.getBasicTypeForJavaType(Double.class);
final BasicType<BigInteger> bigIntegerType = typeConfiguration.getBasicTypeForJavaType(BigInteger.class);
final BasicType<BigDecimal> bigDecimalType = typeConfiguration.getBasicTypeForJavaType(BigDecimal.class);
this.longType = longType;
this.doubleType = doubleType;
this.bigIntegerType = bigIntegerType;
this.bigDecimalType = bigDecimalType;
}
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
return resolveFunctionReturnType( impliedType, null, arguments, typeConfiguration );
}
@Override
public ReturnableType<?> resolveFunctionReturnType(
ReturnableType<?> impliedType,
Supplier<MappingModelExpressible<?>> inferredTypeSupplier,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
if ( impliedType != null ) {
return impliedType;
}
final ReturnableType<?> argType = extractArgumentType( arguments, 1 );
final BasicType<?> basicType;
if (argType instanceof BasicType<?>) {
basicType = (BasicType<?>) argType;
}
else {
basicType = typeConfiguration.getBasicTypeForJavaType( argType.getJavaType() );
if (basicType == null) {
return impliedType;
}
}
switch ( basicType.getJdbcType().getDefaultSqlTypeCode() ) {
case SMALLINT:
case TINYINT:
case INTEGER:
case BIGINT:
return longType;
case FLOAT:
case REAL:
case DOUBLE:
return doubleType;
case DECIMAL:
case NUMERIC:
return BigInteger.class.isAssignableFrom( basicType.getJavaType() ) ? bigIntegerType : bigDecimalType;
case VECTOR:
return basicType;
}
return bigDecimalType;
}
@Override
public BasicValuedMapping resolveFunctionReturnType(
Supplier<BasicValuedMapping> impliedTypeAccess,
List<? extends SqlAstNode> arguments) {
if (impliedTypeAccess != null) {
final BasicValuedMapping basicValuedMapping = impliedTypeAccess.get();
if (basicValuedMapping != null) {
return basicValuedMapping;
}
}
// Resolve according to JPA spec 4.8.5
final BasicValuedMapping specifiedArgType = extractArgumentValuedMapping( arguments, 1 );
final JdbcMapping jdbcMapping = specifiedArgType.getJdbcMapping();
switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
case SMALLINT:
case TINYINT:
case INTEGER:
case BIGINT:
return longType;
case FLOAT:
case REAL:
case DOUBLE:
return doubleType;
case DECIMAL:
case NUMERIC:
final Class<?> argTypeClass = jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass();
return BigInteger.class.isAssignableFrom( argTypeClass ) ? bigIntegerType : bigDecimalType;
case VECTOR:
return (BasicValuedMapping) jdbcMapping;
}
return bigDecimalType;
}
}