HHH-13785 : HQL/Criteria function support
- temporal literals - generalized literals - literal formatters (SQL string generation) - FORMAT function
This commit is contained in:
parent
6e0d15b134
commit
eab6107ec2
|
@ -0,0 +1,33 @@
|
|||
= Query
|
||||
|
||||
== Expressions
|
||||
|
||||
=== Paths
|
||||
|
||||
=== Literals
|
||||
|
||||
=== Parameters
|
||||
|
||||
=== Unary expressions
|
||||
|
||||
=== Arithmetic operations
|
||||
|
||||
Numeric v. temporal
|
||||
|
||||
=== Functions
|
||||
|
||||
- Standard functions
|
||||
- SqmFunctionRegistry
|
||||
- Role of Dialect
|
||||
|
||||
=== Concatenation operations
|
||||
|
||||
=== Entity-type references
|
||||
|
||||
=== CASE statements
|
||||
|
||||
=== COALESCE statements
|
||||
|
||||
=== NULLIF statements
|
||||
|
||||
=== Sub-queries
|
|
@ -0,0 +1,10 @@
|
|||
`OffsetDateTime` is not safe to store in database. This form does not understand "zone rules" relating to things
|
||||
such as DST. An offset of +5, e.g., does not change when DST starts/ends - its just +5.
|
||||
|
||||
A `ZonedDateTime` on the other hand knows the actual timezone as well as the offset for the LocalDateTime portion in
|
||||
that timezone. It is much more complete picture of the actual Instant.
|
||||
|
||||
The proper solution for storing "with tz" would be to always use a `ZonedDateTime`, converted from `OffsetDateTime`
|
||||
if needed. In this case, I assume we need to transform a `LocalDateTime` to `ZonedDateTime`?
|
||||
|
||||
^^ what about Dialects that do not support "with tz" datatype variants? Are there any anymore?
|
|
@ -13,7 +13,7 @@ ext {
|
|||
junitVintageVersion = '5.3.1'
|
||||
junit5Version = '5.3.1'
|
||||
|
||||
h2Version = '1.4.196'
|
||||
h2Version = '1.4.199'
|
||||
bytemanVersion = '4.0.8' //Compatible with JDK14
|
||||
jnpVersion = '5.0.6.CR1'
|
||||
|
||||
|
|
|
@ -11,60 +11,91 @@ lexer grammar HqlLexer;
|
|||
package org.hibernate.grammars.hql;
|
||||
}
|
||||
|
||||
WS : ( ' ' | '\t' | '\f' | EOL ) -> skip;
|
||||
WS : WS_CHAR+ -> skip;
|
||||
|
||||
fragment
|
||||
EOL : [\r\n]+;
|
||||
|
||||
INTEGER_LITERAL : INTEGER_NUMBER ;
|
||||
WS_CHAR : [ \f\t\r\n];
|
||||
|
||||
fragment
|
||||
INTEGER_NUMBER : ('0' | '1'..'9' '0'..'9'*) ;
|
||||
|
||||
LONG_LITERAL : INTEGER_NUMBER ('l'|'L');
|
||||
|
||||
BIG_INTEGER_LITERAL : INTEGER_NUMBER ('bi'|'BI') ;
|
||||
|
||||
HEX_LITERAL : '0' ('x'|'X') HEX_DIGIT+ ('l'|'L')? ;
|
||||
DIGIT : [0-9];
|
||||
|
||||
fragment
|
||||
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
|
||||
HEX_DIGIT : [0-9a-fA-F];
|
||||
|
||||
OCTAL_LITERAL : '0' ('0'..'7')+ ('l'|'L')? ;
|
||||
fragment
|
||||
EXPONENT : [eE] [+-]? DIGIT+;
|
||||
|
||||
FLOAT_LITERAL : FLOATING_POINT_NUMBER ('f'|'F')? ;
|
||||
fragment
|
||||
LONG_SUFFIX : [lL];
|
||||
|
||||
fragment
|
||||
FLOAT_SUFFIX : [fF];
|
||||
|
||||
fragment
|
||||
DOUBLE_SUFFIX : [dD];
|
||||
|
||||
fragment
|
||||
BIG_DECIMAL_SUFFIX : [bB] [dD];
|
||||
|
||||
fragment
|
||||
BIG_INTEGER_SUFFIX : [bB] [iI];
|
||||
|
||||
fragment
|
||||
INTEGER_NUMBER
|
||||
: DIGIT+
|
||||
;
|
||||
|
||||
fragment
|
||||
FLOATING_POINT_NUMBER
|
||||
: ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
|
||||
| '.' ('0'..'9')+ EXPONENT?
|
||||
| ('0'..'9')+ EXPONENT
|
||||
| ('0'..'9')+
|
||||
: DIGIT+ '.' DIGIT* EXPONENT?
|
||||
| '.' DIGIT+ EXPONENT?
|
||||
| DIGIT+ EXPONENT
|
||||
| DIGIT+
|
||||
;
|
||||
|
||||
DOUBLE_LITERAL : FLOATING_POINT_NUMBER ('d'|'D') ;
|
||||
|
||||
BIG_DECIMAL_LITERAL : FLOATING_POINT_NUMBER ('bd'|'BD') ;
|
||||
|
||||
fragment
|
||||
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
|
||||
fragment SINGLE_QUOTE : '\'';
|
||||
fragment DOUBLE_QUOTE : '"';
|
||||
|
||||
CHARACTER_LITERAL
|
||||
: '\'' ( ESCAPE_SEQUENCE | ~('\''|'\\') ) '\'' {setText(getText().substring(1, getText().length()-1));}
|
||||
;
|
||||
|
||||
STRING_LITERAL
|
||||
: '"' ( ESCAPE_SEQUENCE | ~('\\'|'"') )* '"' {setText(getText().substring(1, getText().length()-1));}
|
||||
| ('\'' ( ESCAPE_SEQUENCE | ~('\\'|'\'') )* '\'')+ {setText(getText().substring(1, getText().length()-1).replace("''", "'"));}
|
||||
;
|
||||
fragment BACKSLASH : '\\';
|
||||
|
||||
fragment
|
||||
ESCAPE_SEQUENCE
|
||||
: '\\' ('b'|'t'|'n'|'f'|'r'|'\\"'|'\''|'\\')
|
||||
| UNICODE_ESCAPE
|
||||
| OCTAL_ESCAPE
|
||||
: BACKSLASH [btnfr"']
|
||||
| BACKSLASH UNICODE_ESCAPE
|
||||
| BACKSLASH BACKSLASH
|
||||
;
|
||||
|
||||
fragment
|
||||
UNICODE_ESCAPE
|
||||
: 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
|
||||
;
|
||||
|
||||
INTEGER_LITERAL : INTEGER_NUMBER ;
|
||||
|
||||
LONG_LITERAL : INTEGER_NUMBER LONG_SUFFIX;
|
||||
|
||||
FLOAT_LITERAL : FLOATING_POINT_NUMBER FLOAT_SUFFIX?;
|
||||
|
||||
DOUBLE_LITERAL : FLOATING_POINT_NUMBER DOUBLE_SUFFIX;
|
||||
|
||||
BIG_INTEGER_LITERAL : INTEGER_NUMBER BIG_INTEGER_SUFFIX;
|
||||
|
||||
BIG_DECIMAL_LITERAL : FLOATING_POINT_NUMBER BIG_DECIMAL_SUFFIX;
|
||||
|
||||
HEX_LITERAL : '0' [xX] HEX_DIGIT+ LONG_SUFFIX?;
|
||||
|
||||
OCTAL_LITERAL : '0' ('0'..'7')+ ('l'|'L')? ;
|
||||
|
||||
STRING_LITERAL
|
||||
: DOUBLE_QUOTE ( ~[\\"] | ESCAPE_SEQUENCE | DOUBLE_QUOTE DOUBLE_QUOTE )* DOUBLE_QUOTE
|
||||
{ setText(getText().substring(1, getText().length()-1).replace("\"\"", "\"")); }
|
||||
| SINGLE_QUOTE ( ~[\\'] | ESCAPE_SEQUENCE | SINGLE_QUOTE SINGLE_QUOTE )* SINGLE_QUOTE
|
||||
{ setText(getText().substring(1, getText().length()-1).replace("''", "'")); }
|
||||
;
|
||||
|
||||
|
||||
fragment
|
||||
OCTAL_ESCAPE
|
||||
: '\\' ('0'..'3') ('0'..'7') ('0'..'7')
|
||||
|
@ -72,10 +103,6 @@ OCTAL_ESCAPE
|
|||
| '\\' ('0'..'7')
|
||||
;
|
||||
|
||||
fragment
|
||||
UNICODE_ESCAPE
|
||||
: '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
|
||||
;
|
||||
|
||||
// ESCAPE start tokens
|
||||
TIMESTAMP_ESCAPE_START : '{ts';
|
||||
|
@ -134,6 +161,7 @@ CONCAT : [cC] [oO] [nN] [cC] [aA] [tT];
|
|||
COUNT : [cC] [oO] [uU] [nN] [tT];
|
||||
CROSS : [cC] [rR] [oO] [sS] [sS];
|
||||
CURRENT_DATE : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [dD] [aA] [tT] [eE];
|
||||
CURRENT_DATETIME : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [dD] [aA] [tT] [eE] [tT] [iI] [mM] [eE];
|
||||
CURRENT_INSTANT : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [iI] [nN] [sS] [tT] [aA] [nN] [tT];
|
||||
CURRENT_TIME : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [tT] [iI] [mM] [eE];
|
||||
CURRENT_TIMESTAMP : [cC] [uU] [rR] [rR] [eE] [nN] [tT] '_' [tT] [iI] [mM] [eE] [sS] [tT] [aA] [mM] [pP];
|
||||
|
@ -155,6 +183,7 @@ FETCH : [fF] [eE] [tT] [cC] [hH];
|
|||
FLOOR : [fF] [lL] [oO] [oO] [rR];
|
||||
FROM : [fF] [rR] [oO] [mM];
|
||||
FOR : [fF] [oO] [rR];
|
||||
FORMAT : [fF] [oO] [rR] [mM] [aA] [tT];
|
||||
FULL : [fF] [uU] [lL] [lL];
|
||||
FUNCTION : [fF] [uU] [nN] [cC] [tT] [iI] [oO] [nN];
|
||||
GREATEST : [gG] [rR] [eE] [aA] [tT] [eE] [sS] [tT];
|
||||
|
|
|
@ -466,7 +466,6 @@ nullIf
|
|||
|
||||
literal
|
||||
: STRING_LITERAL
|
||||
| CHARACTER_LITERAL
|
||||
| INTEGER_LITERAL
|
||||
| LONG_LITERAL
|
||||
| BIG_INTEGER_LITERAL
|
||||
|
@ -478,40 +477,79 @@ literal
|
|||
| NULL
|
||||
| TRUE
|
||||
| FALSE
|
||||
| timestampLiteral
|
||||
| dateLiteral
|
||||
| timeLiteral
|
||||
| temporalLiteral
|
||||
| generalizedLiteral
|
||||
;
|
||||
|
||||
// todo (6.0) : expand temporal literal support to Java 8 temporal types
|
||||
// * Instant -> {instant '...'}
|
||||
// * LocalDate -> {localDate '...'}
|
||||
// * LocalDateTime -> {localDateTime '...'}
|
||||
// * OffsetDateTime -> {offsetDateTime '...'}
|
||||
// * OffsetTime -> {offsetTime '...'}
|
||||
// * ZonedDateTime -> {localDate '...'}
|
||||
// * ...
|
||||
//
|
||||
// Few things:
|
||||
// 1) the markers above are just initial thoughts. They are obviously verbose. Maybe acronyms or shortened forms would be better
|
||||
// 2) we may want to stay away from all of the timezone headaches by not supporting local, zoned and offset forms
|
||||
temporalLiteral
|
||||
: dateTimeLiteral
|
||||
| dateLiteral
|
||||
| timeLiteral
|
||||
| jdbcTimestampLiteral
|
||||
| jdbcDateLiteral
|
||||
| jdbcTimeLiteral
|
||||
;
|
||||
|
||||
timestampLiteral
|
||||
: TIMESTAMP_ESCAPE_START dateTimeLiteralText RIGHT_BRACE
|
||||
dateTimeLiteral
|
||||
: LEFT_BRACE dateTime RIGHT_BRACE
|
||||
;
|
||||
|
||||
dateLiteral
|
||||
: DATE_ESCAPE_START dateTimeLiteralText RIGHT_BRACE
|
||||
: LEFT_BRACE date RIGHT_BRACE
|
||||
;
|
||||
|
||||
timeLiteral
|
||||
: TIME_ESCAPE_START dateTimeLiteralText RIGHT_BRACE
|
||||
: LEFT_BRACE time RIGHT_BRACE
|
||||
;
|
||||
|
||||
dateTimeLiteralText
|
||||
: STRING_LITERAL | CHARACTER_LITERAL
|
||||
dateTime
|
||||
: date time (zoneId | offset)?
|
||||
;
|
||||
|
||||
date
|
||||
: year MINUS month MINUS day
|
||||
;
|
||||
|
||||
time
|
||||
: hour COLON minute (COLON second)?
|
||||
;
|
||||
|
||||
offset
|
||||
: (PLUS | MINUS) hour (COLON minute)?
|
||||
;
|
||||
|
||||
year: INTEGER_LITERAL;
|
||||
month: INTEGER_LITERAL;
|
||||
day: INTEGER_LITERAL;
|
||||
hour: INTEGER_LITERAL;
|
||||
minute: INTEGER_LITERAL;
|
||||
second: INTEGER_LITERAL | FLOAT_LITERAL;
|
||||
zoneId: STRING_LITERAL;
|
||||
|
||||
jdbcTimestampLiteral
|
||||
: TIMESTAMP_ESCAPE_START (dateTime | genericTemporalLiteralText) RIGHT_BRACE
|
||||
;
|
||||
|
||||
jdbcDateLiteral
|
||||
: DATE_ESCAPE_START (date | genericTemporalLiteralText) RIGHT_BRACE
|
||||
;
|
||||
|
||||
jdbcTimeLiteral
|
||||
: TIME_ESCAPE_START (time | genericTemporalLiteralText) RIGHT_BRACE
|
||||
;
|
||||
|
||||
genericTemporalLiteralText
|
||||
: STRING_LITERAL
|
||||
;
|
||||
|
||||
generalizedLiteral
|
||||
: LEFT_BRACE generalizedLiteralType COLON generalizedLiteralText RIGHT_BRACE
|
||||
;
|
||||
|
||||
generalizedLiteralType : STRING_LITERAL;
|
||||
generalizedLiteralText : STRING_LITERAL;
|
||||
|
||||
|
||||
parameter
|
||||
: COLON identifier # NamedParameter
|
||||
| QUESTION_MARK INTEGER_LITERAL? # PositionalParameter
|
||||
|
@ -589,6 +627,7 @@ countFunction
|
|||
standardFunction
|
||||
: castFunction
|
||||
| extractFunction
|
||||
| formatFunction
|
||||
| concatFunction
|
||||
| substringFunction
|
||||
| replaceFunction
|
||||
|
@ -666,7 +705,7 @@ trimSpecification
|
|||
;
|
||||
|
||||
trimCharacter
|
||||
: CHARACTER_LITERAL | STRING_LITERAL
|
||||
: STRING_LITERAL
|
||||
;
|
||||
|
||||
upperFunction
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.boot.TempTableDdlTransactionHandling;
|
|||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.H2ExtractEmulation;
|
||||
import org.hibernate.dialect.function.Replacer;
|
||||
import org.hibernate.dialect.hint.IndexQueryHintHandler;
|
||||
import org.hibernate.dialect.identity.H2IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
|
@ -205,6 +206,19 @@ public class H2Dialect extends Dialect {
|
|||
sqlAppender.append(")");
|
||||
}
|
||||
|
||||
public String translateExtractField(TemporalUnit unit) {
|
||||
switch ( unit ) {
|
||||
case DAY_OF_MONTH: return "day";
|
||||
case WEEK: return "iso_week";
|
||||
default: return unit.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
return new Replacer( format, "'", "''" ).replace( "e", "u").result(); //NICE!!
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAddColumnString() {
|
||||
return "add column";
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.Locale;
|
|||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.InformixExtractEmulation;
|
||||
import org.hibernate.dialect.function.Replacer;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.InformixIdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.FirstLimitHandler;
|
||||
|
@ -117,6 +118,65 @@ public class InformixDialect extends Dialect {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
//Informix' own variation of MySQL
|
||||
return datetimeFormat( format ).result();
|
||||
}
|
||||
|
||||
public static Replacer datetimeFormat(String format) {
|
||||
return new Replacer( format, "'", "" )
|
||||
.replace("%", "%%")
|
||||
|
||||
//year
|
||||
.replace("yyyy", "%Y")
|
||||
.replace("yyy", "%Y")
|
||||
.replace("yy", "%y")
|
||||
.replace("y", "Y")
|
||||
|
||||
//month of year
|
||||
.replace("MMMM", "%B")
|
||||
.replace("MMM", "%b")
|
||||
.replace("MM", "%m")
|
||||
.replace("M", "%c") //????
|
||||
|
||||
//day of week
|
||||
.replace("EEEE", "%A")
|
||||
.replace("EEE", "%a")
|
||||
.replace("ee", "%w")
|
||||
.replace("e", "%w")
|
||||
|
||||
//day of month
|
||||
.replace("dd", "%d")
|
||||
.replace("d", "%e")
|
||||
|
||||
//am pm
|
||||
.replace("aa", "%p") //?????
|
||||
.replace("a", "%p") //?????
|
||||
|
||||
//hour
|
||||
.replace("hh", "%I")
|
||||
.replace("HH", "%H")
|
||||
.replace("h", "%I")
|
||||
.replace("H", "%H")
|
||||
|
||||
//minute
|
||||
.replace("mm", "%M")
|
||||
.replace("m", "%M")
|
||||
|
||||
//second
|
||||
.replace("ss", "%S")
|
||||
.replace("s", "%S")
|
||||
|
||||
//fractional seconds
|
||||
.replace("SSSSSS", "%F50") //5 is the max
|
||||
.replace("SSSSS", "%F5")
|
||||
.replace("SSSS", "%F4")
|
||||
.replace("SSS", "%F3")
|
||||
.replace("SS", "%F2")
|
||||
.replace("S", "%F1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAddColumnString() {
|
||||
return "add";
|
||||
|
|
|
@ -188,6 +188,22 @@ public class IngresDialect extends Dialect {
|
|||
sqlAppender.append(")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
return MySQLDialect.datetimeFormat( format ).result();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateExtractField(TemporalUnit unit) {
|
||||
switch ( unit ) {
|
||||
case DAY_OF_MONTH: return "day";
|
||||
case DAY_OF_YEAR: return "doy";
|
||||
case DAY_OF_WEEK: return "dow";
|
||||
case WEEK: return "iso_week";
|
||||
default: return unit.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectGUIDString() {
|
||||
return "select uuid_to_char(uuid_create())";
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.hibernate.boot.TempTableDdlTransactionHandling;
|
|||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.MySQLExtractEmulation;
|
||||
import org.hibernate.dialect.function.Replacer;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.MySQLIdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.AbstractLimitHandler;
|
||||
|
@ -242,6 +243,80 @@ public class MySQLDialect extends Dialect {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
return datetimeFormat( format ).result();
|
||||
}
|
||||
|
||||
public static Replacer datetimeFormat(String format) {
|
||||
return new Replacer( format, "'", "" )
|
||||
.replace("%", "%%")
|
||||
|
||||
//year
|
||||
.replace("yyyy", "%Y")
|
||||
.replace("yyy", "%Y")
|
||||
.replace("yy", "%y")
|
||||
.replace("y", "%Y")
|
||||
|
||||
//month of year
|
||||
.replace("MMMM", "%M")
|
||||
.replace("MMM", "%b")
|
||||
.replace("MM", "%m")
|
||||
.replace("M", "%c")
|
||||
|
||||
//week of year
|
||||
.replace("ww", "%v")
|
||||
.replace("w", "%v")
|
||||
//year for week
|
||||
.replace("YYYY", "%x")
|
||||
.replace("YYY", "%x")
|
||||
.replace("Y", "%x")
|
||||
|
||||
//week of month
|
||||
//????
|
||||
|
||||
//day of week
|
||||
.replace("EEEE", "%W")
|
||||
.replace("EEE", "%a")
|
||||
.replace("ee", "%w")
|
||||
.replace("e", "%w")
|
||||
|
||||
//day of month
|
||||
.replace("dd", "%d")
|
||||
.replace("d", "%e")
|
||||
|
||||
//day of year
|
||||
.replace("DDD", "%j")
|
||||
.replace("DD", "%j")
|
||||
.replace("D", "%j")
|
||||
|
||||
//am pm
|
||||
.replace("aa", "%p")
|
||||
.replace("a", "%p")
|
||||
|
||||
//hour
|
||||
.replace("hh", "%h")
|
||||
.replace("HH", "%H")
|
||||
.replace("h", "%l")
|
||||
.replace("H", "%k")
|
||||
|
||||
//minute
|
||||
.replace("mm", "%i")
|
||||
.replace("m", "%i")
|
||||
|
||||
//second
|
||||
.replace("ss", "%S")
|
||||
.replace("s", "%S")
|
||||
|
||||
//fractional seconds
|
||||
.replace("SSSSSS", "%f")
|
||||
.replace("SSSSS", "%f")
|
||||
.replace("SSSS", "%f")
|
||||
.replace("SSS", "%f")
|
||||
.replace("SS", "%f")
|
||||
.replace("S", "%f");
|
||||
}
|
||||
|
||||
void upgradeTo57() {
|
||||
|
||||
// For details about MySQL 5.7 support for fractional seconds
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.NvlCoalesceEmulation;
|
||||
import org.hibernate.dialect.function.OracleExtractEmulation;
|
||||
import org.hibernate.dialect.function.Replacer;
|
||||
import org.hibernate.dialect.pagination.AbstractLimitHandler;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.LimitHelper;
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.boot.TempTableDdlTransactionHandling;
|
|||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.PostgresExtractEmulation;
|
||||
import org.hibernate.dialect.function.Replacer;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.PostgreSQL81IdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.AbstractLimitHandler;
|
||||
|
|
|
@ -12,12 +12,14 @@ import java.util.Locale;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.Replacer;
|
||||
import org.hibernate.dialect.function.TransactSQLTrimEmulation;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.SQLServerIdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.LegacyLimitHandler;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.TopLimitHandler;
|
||||
import org.hibernate.query.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.type.descriptor.sql.SmallIntTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
|
@ -59,6 +61,58 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
|||
queryEngine.getSqmFunctionRegistry().register( "trim", new TransactSQLTrimEmulation() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateExtractField(TemporalUnit unit) {
|
||||
switch ( unit ) {
|
||||
case WEEK: return "isowk"; //the ISO week number (behavior of "week" depends on a system property)
|
||||
default: return super.translateExtractField(unit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translateDatetimeFormat(String format) {
|
||||
return datetimeFormat(format).result();
|
||||
}
|
||||
|
||||
public static Replacer datetimeFormat(String format) {
|
||||
return new Replacer( format, "'", "\"" )
|
||||
//era
|
||||
.replace("G", "g")
|
||||
|
||||
//y nothing to do
|
||||
//M nothing to do
|
||||
|
||||
//w no equivalent
|
||||
//W no equivalent
|
||||
//Y no equivalent
|
||||
|
||||
//day of week
|
||||
.replace("EEEE", "dddd")
|
||||
.replace("EEE", "ddd")
|
||||
//e no equivalent
|
||||
|
||||
//d nothing to do
|
||||
//D no equivalent
|
||||
|
||||
//am pm
|
||||
.replace("aa", "tt")
|
||||
.replace("a", "tt")
|
||||
|
||||
//h nothing to do
|
||||
//H nothing to do
|
||||
|
||||
//m nothing to do
|
||||
//s nothing to do
|
||||
|
||||
//fractional seconds
|
||||
.replace("S", "F")
|
||||
|
||||
//timezones
|
||||
.replace("XXX", "K") //UTC represented as "Z"
|
||||
.replace("xxx", "zzz")
|
||||
.replace("x", "zz");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNoColumnsInsertString() {
|
||||
return "default values";
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.dialect.function;
|
||||
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.function.StandardFunctionRenderingSupport;
|
||||
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
|
|
@ -4,21 +4,24 @@
|
|||
* 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;
|
||||
package org.hibernate.dialect.function;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
@Internal
|
||||
public class Replacer {
|
||||
private String[] chunks;
|
||||
private String quote;
|
||||
private String delimiter;
|
||||
private List<Replacement> replacements = new ArrayList<>();
|
||||
|
||||
class Replacement {
|
||||
public static class Replacement {
|
||||
String placeholder;
|
||||
String replacement;
|
||||
|
||||
|
@ -45,7 +48,7 @@ public class Replacer {
|
|||
}
|
||||
}
|
||||
|
||||
Replacer(String format, String quote, String delimiter) {
|
||||
public Replacer(String format, String quote, String delimiter) {
|
||||
this.delimiter = delimiter;
|
||||
this.chunks = format.split( quote );
|
||||
this.quote = quote;
|
|
@ -157,7 +157,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
private final boolean[] isNullableTable;
|
||||
private final boolean[] isInverseTable;
|
||||
|
||||
private final Map<String, String> discriminatorValuesByTableName;
|
||||
private final Map<String, Object> discriminatorValuesByTableName;
|
||||
private final Map<String, String> subclassNameByTableName;
|
||||
|
||||
//INITIALIZATION:
|
||||
|
@ -532,7 +532,22 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
|
||||
discriminatorValuesByTableName = new LinkedHashMap<>( subclassSpan + 1 );
|
||||
subclassNameByTableName = new HashMap<>( subclassSpan + 1);
|
||||
discriminatorValuesByTableName.put( persistentClass.getTable().getName(), discriminatorSQLString);
|
||||
// We need to convert the `discriminatorSQLString` (which is a String read from boot-mapping) into
|
||||
// the type indicated by `#discriminatorType` (String -> Integer, e.g.).
|
||||
try {
|
||||
final Object convertedDiscriminatorValue = discriminatorType.stringToObject( discriminatorSQLString );
|
||||
discriminatorValuesByTableName.put( persistentClass.getTable().getName(), convertedDiscriminatorValue );
|
||||
}
|
||||
catch (HibernateException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MappingException(
|
||||
"Could not resolve specified discriminator value [" + discriminatorSQLString
|
||||
+ "] to discriminator type [" + discriminatorType + "]"
|
||||
|
||||
);
|
||||
}
|
||||
discriminatorValues = new String[subclassSpan];
|
||||
discriminatorValues[subclassSpan - 1] = discriminatorSQLString;
|
||||
notNullColumnTableNumbers = new int[subclassSpan];
|
||||
|
@ -590,7 +605,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
// "foo.class = Bar" works in HQL
|
||||
discriminatorValue = sc.getSubclassId();
|
||||
}
|
||||
discriminatorValuesByTableName.put( sc.getTable().getName(), discriminatorValue.toString() );
|
||||
discriminatorValuesByTableName.put( sc.getTable().getName(), discriminatorValue );
|
||||
subclassesByDiscriminatorValue.put( discriminatorValue, sc.getEntityName() );
|
||||
discriminatorValues[k] = discriminatorValue.toString();
|
||||
int id = getTableId(
|
||||
|
@ -1320,8 +1335,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
ColumnReference identifierColumnReference,
|
||||
BasicType resultType) {
|
||||
final Predicate predicate = new NullnessPredicate( identifierColumnReference, true );
|
||||
final Expression expression =
|
||||
new QueryLiteral<>(
|
||||
final Expression expression = new QueryLiteral<>(
|
||||
discriminatorValuesByTableName.get( table.getTableExpression() ),
|
||||
resultType
|
||||
);
|
||||
|
|
|
@ -103,7 +103,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
private final int[] subclassFormulaTableNumberClosure;
|
||||
|
||||
// discriminator column
|
||||
private final Map<Object, String> subclassesByDiscriminatorValue = new HashMap<Object, String>();
|
||||
private final Map<Object, String> subclassesByDiscriminatorValue = new HashMap<>();
|
||||
private final boolean forceDiscriminator;
|
||||
private final String discriminatorColumnName;
|
||||
private final String discriminatorColumnReaders;
|
||||
|
|
|
@ -36,6 +36,9 @@ public enum QueryLiteralRendering {
|
|||
/**
|
||||
* As a parameter when the literal occurs outside the SELECT clause,
|
||||
* otherwise render as a SQL literal.
|
||||
*
|
||||
* Technically this should be called something like AS_PARAM_UNLESS_SELECTED. If the literal is used as an argument
|
||||
* to a function call in the select-clause, for example, we'd still want to render as a parameter.
|
||||
*/
|
||||
AS_PARAM_OUTSIDE_SELECT( "param-outside-select" );
|
||||
|
||||
|
|
|
@ -12,13 +12,19 @@ import java.sql.Date;
|
|||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.NullPrecedence;
|
||||
|
@ -30,6 +36,7 @@ import org.hibernate.grammars.hql.HqlParserBaseVisitor;
|
|||
import org.hibernate.internal.util.collections.Stack;
|
||||
import org.hibernate.internal.util.collections.StandardStack;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
|
@ -67,6 +74,7 @@ import org.hibernate.query.sqm.internal.SqmDmlCreationProcessingState;
|
|||
import org.hibernate.query.sqm.internal.SqmQuerySpecCreationProcessingStateStandardImpl;
|
||||
import org.hibernate.query.sqm.spi.ParameterDeclarationContext;
|
||||
import org.hibernate.query.sqm.spi.SqmCreationContext;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||
|
@ -80,7 +88,6 @@ import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||
import org.hibernate.query.sqm.tree.expression.LiteralHelper;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
|
||||
|
@ -89,6 +96,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
|
||||
|
@ -97,6 +105,7 @@ import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmPathEntityType;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmSelfRenderingExpression;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmStar;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmTrimSpecification;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
|
||||
|
@ -136,7 +145,9 @@ import org.hibernate.query.sqm.tree.select.SqmSelection;
|
|||
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.DateTimeUtils;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -150,6 +161,7 @@ import static org.hibernate.query.TemporalUnit.DAY_OF_MONTH;
|
|||
import static org.hibernate.query.TemporalUnit.DAY_OF_WEEK;
|
||||
import static org.hibernate.query.TemporalUnit.DAY_OF_YEAR;
|
||||
import static org.hibernate.query.TemporalUnit.OFFSET;
|
||||
import static org.hibernate.query.TemporalUnit.SECOND;
|
||||
import static org.hibernate.query.TemporalUnit.TIME;
|
||||
import static org.hibernate.query.TemporalUnit.TIMEZONE_HOUR;
|
||||
import static org.hibernate.query.TemporalUnit.TIMEZONE_MINUTE;
|
||||
|
@ -171,6 +183,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
* Main entry point into analysis of HQL/JPQL parse tree - producing a semantic model of the
|
||||
* query.
|
||||
*/
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static SqmStatement buildSemanticModel(
|
||||
HqlParser.StatementContext hqlParseTree,
|
||||
SqmCreationOptions creationOptions,
|
||||
|
@ -195,6 +208,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return processingStateStack;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public SemanticQueryBuilder(SqmCreationOptions creationOptions, SqmCreationContext creationContext) {
|
||||
this.creationOptions = creationOptions;
|
||||
this.creationContext = creationContext;
|
||||
|
@ -1408,7 +1422,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return new SqmFunction(
|
||||
"mod",
|
||||
getFunctionDescriptor( "mod" ),
|
||||
(AllowableFunctionReturnType) dividend.getNodeType(),
|
||||
dividend.getNodeType(),
|
||||
asList( dividend, divisor ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
@ -1513,7 +1527,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return new SqmFunction(
|
||||
"local_datetime",
|
||||
getFunctionDescriptor( "local_datetime" ),
|
||||
StandardBasicTypes.TIMESTAMP,
|
||||
StandardBasicTypes.LOCAL_DATE_TIME,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
@ -1524,7 +1538,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return new SqmFunction(
|
||||
"local_date",
|
||||
getFunctionDescriptor( "local_date" ),
|
||||
StandardBasicTypes.TIMESTAMP,
|
||||
StandardBasicTypes.LOCAL_DATE,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
@ -1535,7 +1549,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return new SqmFunction(
|
||||
"local_time",
|
||||
getFunctionDescriptor( "local_time" ),
|
||||
StandardBasicTypes.TIMESTAMP,
|
||||
StandardBasicTypes.LOCAL_TIME,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
@ -1568,7 +1582,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return new SqmFunction(
|
||||
"least",
|
||||
getFunctionDescriptor( "least" ),
|
||||
(AllowableFunctionReturnType<?>) type,
|
||||
type,
|
||||
arguments,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
@ -1637,22 +1651,23 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
|
||||
@Override
|
||||
public SqmLiteral visitLiteralExpression(HqlParser.LiteralExpressionContext ctx) {
|
||||
if ( ctx.literal().CHARACTER_LITERAL() != null ) {
|
||||
return characterLiteral( ctx.literal().CHARACTER_LITERAL().getText() );
|
||||
}
|
||||
else if ( ctx.literal().STRING_LITERAL() != null ) {
|
||||
if ( ctx.literal().STRING_LITERAL() != null ) {
|
||||
return stringLiteral( ctx.literal().STRING_LITERAL().getText() );
|
||||
}
|
||||
else if ( ctx.literal().INTEGER_LITERAL() != null ) {
|
||||
|
||||
if ( ctx.literal().INTEGER_LITERAL() != null ) {
|
||||
return integerLiteral( ctx.literal().INTEGER_LITERAL().getText() );
|
||||
}
|
||||
else if ( ctx.literal().LONG_LITERAL() != null ) {
|
||||
|
||||
if ( ctx.literal().LONG_LITERAL() != null ) {
|
||||
return longLiteral( ctx.literal().LONG_LITERAL().getText() );
|
||||
}
|
||||
else if ( ctx.literal().BIG_INTEGER_LITERAL() != null ) {
|
||||
|
||||
if ( ctx.literal().BIG_INTEGER_LITERAL() != null ) {
|
||||
return bigIntegerLiteral( ctx.literal().BIG_INTEGER_LITERAL().getText() );
|
||||
}
|
||||
else if ( ctx.literal().HEX_LITERAL() != null ) {
|
||||
|
||||
if ( ctx.literal().HEX_LITERAL() != null ) {
|
||||
final String text = ctx.literal().HEX_LITERAL().getText();
|
||||
if ( text.endsWith( "l" ) || text.endsWith( "L" ) ) {
|
||||
return longLiteral( text );
|
||||
|
@ -1661,7 +1676,8 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return integerLiteral( text );
|
||||
}
|
||||
}
|
||||
else if ( ctx.literal().OCTAL_LITERAL() != null ) {
|
||||
|
||||
if ( ctx.literal().OCTAL_LITERAL() != null ) {
|
||||
final String text = ctx.literal().OCTAL_LITERAL().getText();
|
||||
if ( text.endsWith( "l" ) || text.endsWith( "L" ) ) {
|
||||
return longLiteral( text );
|
||||
|
@ -1670,56 +1686,379 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
return integerLiteral( text );
|
||||
}
|
||||
}
|
||||
else if ( ctx.literal().FLOAT_LITERAL() != null ) {
|
||||
|
||||
if ( ctx.literal().FLOAT_LITERAL() != null ) {
|
||||
return floatLiteral( ctx.literal().FLOAT_LITERAL().getText() );
|
||||
}
|
||||
else if ( ctx.literal().DOUBLE_LITERAL() != null ) {
|
||||
|
||||
if ( ctx.literal().DOUBLE_LITERAL() != null ) {
|
||||
return doubleLiteral( ctx.literal().DOUBLE_LITERAL().getText() );
|
||||
}
|
||||
else if ( ctx.literal().BIG_DECIMAL_LITERAL() != null ) {
|
||||
|
||||
if ( ctx.literal().BIG_DECIMAL_LITERAL() != null ) {
|
||||
return bigDecimalLiteral( ctx.literal().BIG_DECIMAL_LITERAL().getText() );
|
||||
}
|
||||
else if ( ctx.literal().FALSE() != null ) {
|
||||
|
||||
if ( ctx.literal().FALSE() != null ) {
|
||||
return booleanLiteral( false );
|
||||
}
|
||||
else if ( ctx.literal().TRUE() != null ) {
|
||||
|
||||
if ( ctx.literal().TRUE() != null ) {
|
||||
return booleanLiteral( true );
|
||||
}
|
||||
else if ( ctx.literal().NULL() != null ) {
|
||||
|
||||
if ( ctx.literal().NULL() != null ) {
|
||||
return new SqmLiteralNull( creationContext.getQueryEngine().getCriteriaBuilder() );
|
||||
}
|
||||
else if ( ctx.literal().timestampLiteral() != null ) {
|
||||
return LiteralHelper.timestampLiteralFrom( ctx.literal().timestampLiteral().dateTimeLiteralText().getText(), this );
|
||||
|
||||
if ( ctx.literal().temporalLiteral() != null ) {
|
||||
return interpretTemporalLiteral( ctx.literal().temporalLiteral() );
|
||||
}
|
||||
else if ( ctx.literal().dateLiteral() != null ) {
|
||||
return LiteralHelper.dateLiteralFrom( ctx.literal().dateLiteral().dateTimeLiteralText().getText(), this );
|
||||
}
|
||||
else if ( ctx.literal().timeLiteral() != null ) {
|
||||
return LiteralHelper.timeLiteralFrom( ctx.literal().timeLiteral().dateTimeLiteralText().getText(), this );
|
||||
|
||||
if ( ctx.literal().generalizedLiteral() != null ) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
// otherwise we have a problem
|
||||
throw new ParsingException( "Unexpected literal expression type [" + ctx.getText() + "]" );
|
||||
}
|
||||
|
||||
private SqmLiteral interpretTemporalLiteral(HqlParser.TemporalLiteralContext temporalLiteral) {
|
||||
if ( temporalLiteral.dateTimeLiteral() != null ) {
|
||||
return interpretDateTimeLiteral( temporalLiteral.dateTimeLiteral() );
|
||||
}
|
||||
|
||||
if ( temporalLiteral.dateLiteral() != null ) {
|
||||
return interpretDateLiteral( temporalLiteral.dateLiteral() );
|
||||
}
|
||||
|
||||
if ( temporalLiteral.timeLiteral() != null ) {
|
||||
return interpretTimeLiteral( temporalLiteral.timeLiteral() );
|
||||
}
|
||||
|
||||
if ( temporalLiteral.jdbcTimestampLiteral() != null ) {
|
||||
return interpretJdbcDateTimeLiteral( temporalLiteral.jdbcTimestampLiteral() );
|
||||
}
|
||||
|
||||
if ( temporalLiteral.jdbcDateLiteral() != null ) {
|
||||
return interpretJdbcDateLiteral( temporalLiteral.jdbcDateLiteral() );
|
||||
}
|
||||
|
||||
if ( temporalLiteral.jdbcTimeLiteral() != null ) {
|
||||
return interpretJdbcTimeLiteral( temporalLiteral.jdbcTimeLiteral() );
|
||||
}
|
||||
|
||||
// otherwise we have a problem
|
||||
throw new ParsingException( "Could not interpret temporal literal expression [" + temporalLiteral.getText() + "]" );
|
||||
}
|
||||
|
||||
private SqmLiteral interpretDateTimeLiteral(HqlParser.DateTimeLiteralContext dateTimeLiteral) {
|
||||
final HqlParser.DateTimeContext dateTimeCtx = dateTimeLiteral.dateTime();
|
||||
|
||||
final HqlParser.DateContext dateCtx = dateTimeCtx.date();
|
||||
final HqlParser.TimeContext timeCtx = dateTimeCtx.time();
|
||||
|
||||
final LocalDate localDate = localDate( dateCtx );
|
||||
final LocalTime localTime = localTime( timeCtx );
|
||||
|
||||
if ( dateTimeCtx.zoneId() == null && dateTimeCtx.offset() == null ) {
|
||||
return new SqmLiteral<>(
|
||||
LocalDateTime.of( localDate, localTime ),
|
||||
basicType( LocalDateTime.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
if ( dateTimeCtx.zoneId() != null ) {
|
||||
// we have a "zone id", which could still identify an offset rather that a ZoneId
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return new SqmLiteral(
|
||||
ZonedDateTime.of(
|
||||
localDate,
|
||||
localTime,
|
||||
ZoneId.of( dateTimeCtx.zoneId().STRING_LITERAL().getText() )
|
||||
),
|
||||
basicType( OffsetDateTime.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
catch (Exception e) {
|
||||
//noinspection unchecked
|
||||
return new SqmLiteral(
|
||||
ZonedDateTime.of(
|
||||
localDate,
|
||||
localTime,
|
||||
TimeZone.getTimeZone( dateTimeCtx.zoneId().STRING_LITERAL().getText() ).toZoneId()
|
||||
),
|
||||
basicType( ZonedDateTime.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final HqlParser.OffsetContext offsetCtx = dateTimeCtx.offset();
|
||||
assert offsetCtx != null;
|
||||
|
||||
// handle the offset
|
||||
final int hourCtx = Integer.parseInt( offsetCtx.hour().INTEGER_LITERAL().getText() );
|
||||
final int hour = offsetCtx.MINUS() == null
|
||||
? hourCtx
|
||||
: 0 - hourCtx;
|
||||
final ZoneOffset offset = ZoneOffset.ofHoursMinutes(
|
||||
hour,
|
||||
offsetCtx.minute() == null
|
||||
? 0
|
||||
: Integer.parseInt( offsetCtx.minute().INTEGER_LITERAL().getText() )
|
||||
);
|
||||
|
||||
//noinspection unchecked
|
||||
return new SqmLiteral(
|
||||
OffsetDateTime.of( localDate, localTime, offset ),
|
||||
basicType( OffsetDateTime.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral interpretJdbcDateTimeLiteral(HqlParser.JdbcTimestampLiteralContext jdbcDateTimeLiteralCtx) {
|
||||
final Timestamp timestamp;
|
||||
|
||||
if ( jdbcDateTimeLiteralCtx.genericTemporalLiteralText() != null ) {
|
||||
final TemporalAccessor parsed = DateTimeUtils.DATE_TIME.parseBest(
|
||||
jdbcDateTimeLiteralCtx.genericTemporalLiteralText().STRING_LITERAL().getText(),
|
||||
OffsetDateTime::from,
|
||||
ZonedDateTime::from,
|
||||
LocalDateTime::from
|
||||
);
|
||||
|
||||
if ( parsed instanceof LocalDateTime ) {
|
||||
final LocalDateTime localDateTime = (LocalDateTime) parsed;
|
||||
|
||||
//noinspection deprecation
|
||||
timestamp = new Timestamp(
|
||||
localDateTime.getYear(),
|
||||
localDateTime.getMonthValue(),
|
||||
localDateTime.getDayOfMonth(),
|
||||
localDateTime.getHour(),
|
||||
localDateTime.getMinute(),
|
||||
localDateTime.getSecond(),
|
||||
localDateTime.getNano()
|
||||
);
|
||||
}
|
||||
else if ( parsed instanceof OffsetDateTime ) {
|
||||
timestamp = new Timestamp( ( (OffsetDateTime) parsed ).toInstant().toEpochMilli() );
|
||||
}
|
||||
else {
|
||||
assert parsed instanceof ZonedDateTime;
|
||||
timestamp = new Timestamp( ( (ZonedDateTime) parsed ).toInstant().toEpochMilli() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
final HqlParser.DateTimeContext dateTimeCtx = jdbcDateTimeLiteralCtx.dateTime();
|
||||
assert dateTimeCtx != null;
|
||||
|
||||
final LocalDateTime localDateTime = LocalDateTime.of(
|
||||
localDate( dateTimeCtx.date() ),
|
||||
localTime( dateTimeCtx.time() )
|
||||
);
|
||||
|
||||
if ( dateTimeCtx.zoneId() == null && dateTimeCtx.offset() == null ) {
|
||||
// todo (6.0) : use local-tz or jdbc-tz as offset?
|
||||
// for now, just use UTC
|
||||
|
||||
timestamp = new Timestamp( localDateTime.toInstant( ZoneOffset.UTC ).toEpochMilli() );
|
||||
|
||||
// below is another option
|
||||
// timestamp = new Timestamp(
|
||||
// localDateTime.getYear(),
|
||||
// localDateTime.getMonthValue(),
|
||||
// localDateTime.getDayOfMonth(),
|
||||
// localDateTime.getHour(),
|
||||
// localDateTime.getMinute(),
|
||||
// localDateTime.getSecond(),
|
||||
// localDateTime.getNano()
|
||||
// );
|
||||
}
|
||||
else if ( dateTimeCtx.zoneId() != null ) {
|
||||
// we have a "zone id", which could still identify an offset rather that a ZoneId
|
||||
ZoneId zoneId;
|
||||
try {
|
||||
zoneId = ZoneId.of( dateTimeCtx.zoneId().STRING_LITERAL().getText() );
|
||||
}
|
||||
catch (Exception e) {
|
||||
zoneId = TimeZone.getTimeZone( dateTimeCtx.zoneId().STRING_LITERAL().getText() ).toZoneId();
|
||||
//noinspection unchecked
|
||||
return new SqmLiteral(
|
||||
ZonedDateTime.of( localDateTime, zoneId ),
|
||||
basicType( OffsetDateTime.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
timestamp = new Timestamp( ZonedDateTime.of( localDateTime, zoneId ).toInstant().toEpochMilli() );
|
||||
}
|
||||
else {
|
||||
assert dateTimeCtx.offset() != null;
|
||||
|
||||
final HqlParser.OffsetContext offsetCtx = dateTimeCtx.offset();
|
||||
assert offsetCtx != null;
|
||||
|
||||
// handle the offset
|
||||
final int hourCtx = Integer.parseInt( offsetCtx.hour().INTEGER_LITERAL().getText() );
|
||||
final int hour = offsetCtx.MINUS() == null
|
||||
? hourCtx
|
||||
: 0 - hourCtx;
|
||||
final ZoneOffset offset = ZoneOffset.ofHoursMinutes(
|
||||
hour,
|
||||
offsetCtx.minute() == null
|
||||
? 0
|
||||
: Integer.parseInt( offsetCtx.minute().INTEGER_LITERAL().getText() )
|
||||
);
|
||||
|
||||
timestamp = new Timestamp( OffsetDateTime.of( localDateTime, offset ).toInstant().toEpochMilli() );
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return new SqmLiteral( timestamp, basicType( Timestamp.class ), creationContext.getNodeBuilder() );
|
||||
}
|
||||
|
||||
private <J> BasicDomainType<J> basicType(Class<J> javaType) {
|
||||
//noinspection unchecked
|
||||
return creationContext.getJpaMetamodel().getTypeConfiguration().standardBasicTypeForJavaType( javaType );
|
||||
}
|
||||
|
||||
private static LocalDate localDate(HqlParser.DateContext ctx) {
|
||||
return LocalDate.of(
|
||||
Integer.parseInt( ctx.year().getText() ),
|
||||
Integer.parseInt( ctx.month().getText() ),
|
||||
Integer.parseInt( ctx.day().getText() )
|
||||
);
|
||||
}
|
||||
|
||||
private static LocalTime localTime(HqlParser.TimeContext ctx) {
|
||||
if ( ctx.second() != null ) {
|
||||
int index = ctx.second().getText().indexOf('.');
|
||||
if ( index < 0 ) {
|
||||
return LocalTime.of(
|
||||
Integer.parseInt( ctx.hour().getText() ),
|
||||
Integer.parseInt( ctx.minute().getText() ),
|
||||
Integer.parseInt( ctx.second().getText() )
|
||||
);
|
||||
}
|
||||
else {
|
||||
return LocalTime.of(
|
||||
Integer.parseInt( ctx.hour().getText() ),
|
||||
Integer.parseInt( ctx.minute().getText() ),
|
||||
Integer.parseInt( ctx.second().getText().substring( 0, index ) ),
|
||||
Integer.parseInt( ctx.second().getText().substring( index + 1 ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return LocalTime.of(
|
||||
Integer.parseInt( ctx.hour().getText() ),
|
||||
Integer.parseInt( ctx.minute().getText() )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private SqmLiteral interpretDateLiteral(HqlParser.DateLiteralContext dateLiteral) {
|
||||
//noinspection unchecked
|
||||
return new SqmLiteral(
|
||||
localDate( dateLiteral.date() ),
|
||||
basicType( LocalDate.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral interpretJdbcDateLiteral(HqlParser.JdbcDateLiteralContext dateLiteral) {
|
||||
if ( dateLiteral.genericTemporalLiteralText() != null ) {
|
||||
final LocalDate parsed = DateTimeUtils.DATE.parse(
|
||||
dateLiteral.genericTemporalLiteralText().STRING_LITERAL().getText(),
|
||||
LocalDate::from
|
||||
);
|
||||
|
||||
//noinspection unchecked,deprecation
|
||||
return new SqmLiteral(
|
||||
new Date( parsed.getYear(), parsed.getMonthValue(), parsed.getDayOfMonth() ),
|
||||
basicType( Date.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
final HqlParser.DateContext dateCtx = dateLiteral.date();
|
||||
|
||||
//noinspection unchecked,deprecation
|
||||
return new SqmLiteral(
|
||||
new Date(
|
||||
Integer.parseInt( dateCtx.year().INTEGER_LITERAL().getText() ),
|
||||
Integer.parseInt( dateCtx.month().INTEGER_LITERAL().getText() ),
|
||||
Integer.parseInt( dateCtx.day().INTEGER_LITERAL().getText() )
|
||||
),
|
||||
basicType( Date.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral interpretTimeLiteral(HqlParser.TimeLiteralContext timeLiteral) {
|
||||
//noinspection unchecked
|
||||
return new SqmLiteral(
|
||||
localTime( timeLiteral.time() ),
|
||||
basicType( LocalTime.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral interpretJdbcTimeLiteral(HqlParser.JdbcTimeLiteralContext timeLiteral) {
|
||||
if ( timeLiteral.genericTemporalLiteralText() != null ) {
|
||||
final LocalTime parsed = DateTimeUtils.TIME.parse(
|
||||
timeLiteral.genericTemporalLiteralText().STRING_LITERAL().getText(),
|
||||
LocalTime::from
|
||||
);
|
||||
|
||||
//noinspection unchecked,deprecation
|
||||
return new SqmLiteral(
|
||||
new Time( parsed.getHour(), parsed.getMinute(), parsed.getSecond() ),
|
||||
basicType( Time.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
final int seconds;
|
||||
|
||||
if ( timeLiteral.time().second().FLOAT_LITERAL() == null ) {
|
||||
seconds = Integer.parseInt( timeLiteral.time().second().INTEGER_LITERAL().getText() );
|
||||
}
|
||||
else {
|
||||
final float floatValue = Float.parseFloat( timeLiteral.time().second().FLOAT_LITERAL().getText() );
|
||||
log.debugf( "Float-value encountered for seconds part of JDBC Date literal - ignoring fractional : " + floatValue );
|
||||
seconds = (int) floatValue;
|
||||
}
|
||||
|
||||
//noinspection unchecked,deprecation
|
||||
return new SqmLiteral(
|
||||
new Time(
|
||||
Integer.parseInt( timeLiteral.time().hour().INTEGER_LITERAL().getText() ),
|
||||
Integer.parseInt( timeLiteral.time().minute().INTEGER_LITERAL().getText() ),
|
||||
seconds
|
||||
),
|
||||
basicType( Time.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmLiteral visitGeneralizedLiteral(HqlParser.GeneralizedLiteralContext ctx) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
private SqmLiteral<Boolean> booleanLiteral(boolean value) {
|
||||
final SqmExpressable expressionType = resolveExpressableTypeBasic( Boolean.class );
|
||||
//noinspection unchecked
|
||||
return new SqmLiteral<>( value, expressionType, creationContext.getQueryEngine().getCriteriaBuilder() );
|
||||
}
|
||||
|
||||
private SqmLiteral<Character> characterLiteral(String text) {
|
||||
if ( text.length() > 1 ) {
|
||||
// todo : or just treat it as a String literal?
|
||||
throw new ParsingException( "Value for CHARACTER_LITERAL token was more than 1 character" );
|
||||
}
|
||||
return new SqmLiteral<>(
|
||||
text.charAt( 0 ),
|
||||
resolveExpressableTypeBasic( Character.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmLiteral<String> stringLiteral(String text) {
|
||||
return new SqmLiteral<>(
|
||||
text,
|
||||
|
@ -2208,7 +2547,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
|
||||
@Override
|
||||
public Object visitDayField(HqlParser.DayFieldContext ctx) {
|
||||
NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
|
||||
final NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
|
||||
if ( ctx.WEEK() != null ) {
|
||||
return new SqmExtractUnit<>( DAY_OF_WEEK, resolveExpressableTypeBasic( Integer.class ), nodeBuilder );
|
||||
}
|
||||
|
@ -2223,7 +2562,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
|
||||
@Override
|
||||
public Object visitWeekField(HqlParser.WeekFieldContext ctx) {
|
||||
NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
|
||||
final NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
|
||||
if ( ctx.MONTH() != null ) {
|
||||
//this is computed from DAY_OF_MONTH/7
|
||||
return new SqmExtractUnit<>( WEEK_OF_MONTH, resolveExpressableTypeBasic( Integer.class ), nodeBuilder );
|
||||
|
@ -2270,27 +2609,245 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
private boolean isExtractingJdbcTemporalType;
|
||||
|
||||
@Override
|
||||
public Object visitExtractFunction(HqlParser.ExtractFunctionContext ctx) {
|
||||
final SqmExpression<?> expressionToExtract = (SqmExpression) ctx.expression().accept( this );
|
||||
final SqmExtractUnit<?> extractFieldExpression;
|
||||
public Object visitExtractFunction(HqlParser.ExtractFunctionContext extractFunctionCtx) {
|
||||
final SqmExpression<?> sqmTemporalExpr = (SqmExpression) extractFunctionCtx.expression().accept( this );
|
||||
final SqmExtractUnit<?> sqmExtractUnit;
|
||||
|
||||
if ( ctx.extractField() != null ) {
|
||||
extractFieldExpression = (SqmExtractUnit) ctx.extractField().accept( this);
|
||||
// Allow `#visitDateOrTimeField()` to know if we're extracting from a JDBC Timestamp or from a
|
||||
// java.time LocalDateTime/OffsetDateTime
|
||||
isExtractingJdbcTemporalType = isJdbcTemporalType( sqmTemporalExpr.getNodeType() );
|
||||
|
||||
if ( extractFunctionCtx.extractField() != null ) {
|
||||
// for the case of the full ANSI syntax "extract(field from arg)"
|
||||
sqmExtractUnit = (SqmExtractUnit) extractFunctionCtx.extractField().accept( this);
|
||||
}
|
||||
else if ( ctx.datetimeField() != null ) {
|
||||
isExtractingJdbcTemporalType = isJdbcTemporalType( expressionToExtract.getNodeType() );
|
||||
extractFieldExpression = (SqmExtractUnit) ctx.datetimeField().accept( this );
|
||||
else if ( extractFunctionCtx.datetimeField() != null ) {
|
||||
// for the shorter legacy Hibernate syntax "field(arg)"
|
||||
sqmExtractUnit = (SqmExtractUnit) extractFunctionCtx.datetimeField().accept( this );
|
||||
}
|
||||
else {
|
||||
return expressionToExtract;
|
||||
return sqmTemporalExpr;
|
||||
}
|
||||
|
||||
final TemporalUnit unit = sqmExtractUnit.getTemporalUnit();
|
||||
switch ( unit ) {
|
||||
case NANOSECOND: {
|
||||
return extractNanoseconds( sqmTemporalExpr );
|
||||
}
|
||||
case OFFSET: {
|
||||
// use formatdatetime(arg, 'xxx') to get the offset
|
||||
return extractOffsetUsingFormat( sqmTemporalExpr );
|
||||
}
|
||||
case DATE:
|
||||
case TIME: {
|
||||
// use cast(arg as Type) to get the date or time part
|
||||
// which might be javax.sql.Date / javax.sql.Time or
|
||||
// java.time.LocalDate / java.time.LocalTime depending
|
||||
// on the type of the expression we're extracting from
|
||||
return extractDateOrTimeUsingCast(
|
||||
sqmTemporalExpr,
|
||||
sqmExtractUnit.getType()
|
||||
);
|
||||
}
|
||||
case WEEK_OF_MONTH: {
|
||||
// use ceiling(extract(day of month, arg)/7.0)
|
||||
return extractWeek( sqmTemporalExpr, DAY_OF_MONTH );
|
||||
}
|
||||
case WEEK_OF_YEAR: {
|
||||
// use ceiling(extract(day of year, arg)/7.0)
|
||||
return extractWeek( sqmTemporalExpr, DAY_OF_YEAR );
|
||||
}
|
||||
default: {
|
||||
// otherwise it's something we expect the SQL dialect
|
||||
// itself to understand, either natively, or via the
|
||||
// registered function template for extract()
|
||||
|
||||
//noinspection unchecked
|
||||
return new SqmFunction(
|
||||
"extract",
|
||||
getFunctionDescriptor( "extract" ),
|
||||
extractFieldExpression.getNodeType(),
|
||||
asList( extractFieldExpression, expressionToExtract ),
|
||||
sqmExtractUnit.getNodeType(),
|
||||
asList( sqmExtractUnit, sqmTemporalExpr ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SqmExpression<Long> extractNanoseconds(SqmExpression<?> sqmTemporalExpr) {
|
||||
final SqmFunctionDescriptor roundFunctionDescriptor = getFunctionDescriptor( "round" );
|
||||
final SqmFunctionDescriptor extractFunctionDescriptor = getFunctionDescriptor( "extract" );
|
||||
|
||||
final SqmLiteral<Float> nanoMultiplierLiteral = floatLiteral( "1e9" );
|
||||
final SqmLiteral<Integer> zeroLiteral = integerLiteral( "0" );
|
||||
|
||||
final SqmSelfRenderingExpression<Long> sqmExtractSeconds = new SqmSelfRenderingExpression<>(
|
||||
semanticQueryWalker -> extractFunctionDescriptor.generateSqlExpression(
|
||||
"extract",
|
||||
asList(
|
||||
new SqmExtractUnit<>(
|
||||
SECOND,
|
||||
StandardBasicTypes.INTEGER,
|
||||
creationContext.getNodeBuilder()
|
||||
),
|
||||
sqmTemporalExpr
|
||||
),
|
||||
() -> (MappingModelExpressable) basicType( Long.class ),
|
||||
(SqmToSqlAstConverter) semanticQueryWalker,
|
||||
(SqlAstCreationState) semanticQueryWalker
|
||||
),
|
||||
basicType( Long.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
||||
return new SqmSelfRenderingExpression<>(
|
||||
semanticQueryWalker -> roundFunctionDescriptor.generateSqlExpression(
|
||||
"round",
|
||||
asList(
|
||||
new SqmBinaryArithmetic<>(
|
||||
BinaryArithmeticOperator.MULTIPLY,
|
||||
sqmExtractSeconds,
|
||||
nanoMultiplierLiteral,
|
||||
basicType( Float.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
),
|
||||
zeroLiteral
|
||||
),
|
||||
() -> (MappingModelExpressable) basicType( Float.class ),
|
||||
(SqmToSqlAstConverter) semanticQueryWalker,
|
||||
(SqlAstCreationState) semanticQueryWalker
|
||||
),
|
||||
basicType( Long.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmExpression<?> extractDateOrTimeUsingCast(
|
||||
SqmExpression<?> expressionToExtract,
|
||||
AllowableFunctionReturnType<?> type) {
|
||||
return new SqmFunction<>(
|
||||
"cast",
|
||||
getFunctionDescriptor( "cast" ),
|
||||
type,
|
||||
asList(
|
||||
expressionToExtract,
|
||||
new SqmCastTarget<>(
|
||||
type,
|
||||
creationContext.getNodeBuilder()
|
||||
)
|
||||
),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmExpression<ZoneOffset> extractOffsetUsingFormat(SqmExpression<?> expressionToExtract) {
|
||||
return new SqmFunction<>(
|
||||
"formatdatetime",
|
||||
getFunctionDescriptor( "formatdatetime" ),
|
||||
basicType( ZoneOffset.class ),
|
||||
asList(
|
||||
expressionToExtract,
|
||||
new SqmFormat(
|
||||
"xxx", //pattern for timezone offset
|
||||
basicType( String.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
)
|
||||
),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
private SqmExpression<Integer> extractWeek(
|
||||
SqmExpression<?> expressionToExtract,
|
||||
TemporalUnit dayOf) {
|
||||
final BasicDomainType<Integer> intType = basicType( Integer.class );
|
||||
|
||||
final SqmFunctionDescriptor extractFunctionDescriptor = getFunctionDescriptor( "extract" );
|
||||
|
||||
final SqmFunction<Integer> extractDayOf = new SqmFunction<>(
|
||||
"extract",
|
||||
extractFunctionDescriptor,
|
||||
intType,
|
||||
asList(
|
||||
new SqmExtractUnit<>(
|
||||
dayOf,
|
||||
intType,
|
||||
creationContext.getNodeBuilder()
|
||||
),
|
||||
expressionToExtract
|
||||
),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
||||
final SqmFunction<Integer> extractDayOfWeek = new SqmFunction<>(
|
||||
"extract",
|
||||
extractFunctionDescriptor,
|
||||
intType,
|
||||
asList(
|
||||
new SqmExtractUnit<>(
|
||||
DAY_OF_WEEK,
|
||||
intType,
|
||||
creationContext.getNodeBuilder()
|
||||
),
|
||||
expressionToExtract
|
||||
),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
||||
final SqmBinaryArithmetic<Integer> subtraction = new SqmBinaryArithmetic<>(
|
||||
BinaryArithmeticOperator.SUBTRACT,
|
||||
extractDayOf,
|
||||
extractDayOfWeek,
|
||||
intType,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
||||
final SqmBinaryArithmetic<Float> division = new SqmBinaryArithmetic<>(
|
||||
BinaryArithmeticOperator.DIVIDE,
|
||||
subtraction,
|
||||
floatLiteral( "7.0" ),
|
||||
basicType( Float.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
|
||||
return new SqmBinaryArithmetic<>(
|
||||
BinaryArithmeticOperator.ADD,
|
||||
new SqmFunction<>(
|
||||
"ceiling",
|
||||
getFunctionDescriptor( "ceiling" ),
|
||||
intType,
|
||||
Collections.singletonList( division ),
|
||||
creationContext.getNodeBuilder()
|
||||
),
|
||||
integerLiteral("1"),
|
||||
intType,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmFunction visitFormatFunction(HqlParser.FormatFunctionContext ctx) {
|
||||
final SqmExpression<?> expressionToCast = (SqmExpression) ctx.expression().accept( this );
|
||||
final SqmFormat format = visitFormat( ctx.format() );
|
||||
|
||||
return new SqmFunction<>(
|
||||
"formatdatetime",
|
||||
getFunctionDescriptor( "formatdatetime" ),
|
||||
basicType( String.class ),
|
||||
asList( expressionToCast, format ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmFormat visitFormat(HqlParser.FormatContext ctx) {
|
||||
final String formatPattern = ctx.STRING_LITERAL().getText();
|
||||
// if (!FORMAT.matcher(format).matches()) {
|
||||
// throw new SemanticException("illegal format pattern: '" + format + "'");
|
||||
// }
|
||||
return new SqmFormat(
|
||||
formatPattern,
|
||||
basicType( String.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
@ -2633,20 +3190,6 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
|
||||
@Override
|
||||
public SqmLiteral<Character> visitTrimCharacter(HqlParser.TrimCharacterContext ctx) {
|
||||
// todo (6.0) : we should delay this until we are walking the SQM
|
||||
|
||||
if ( ctx.CHARACTER_LITERAL() != null ) {
|
||||
final String trimCharText = ctx.CHARACTER_LITERAL().getText();
|
||||
if ( trimCharText.length() != 1 ) {
|
||||
throw new SemanticException( "Expecting [trim character] for TRIM function to be single character, found : " + trimCharText );
|
||||
}
|
||||
return new SqmLiteral<>(
|
||||
trimCharText.charAt( 0 ),
|
||||
resolveExpressableTypeBasic( Character.class ),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
if ( ctx.STRING_LITERAL() != null ) {
|
||||
final String trimCharText = ctx.STRING_LITERAL().getText();
|
||||
if ( trimCharText.length() != 1 ) {
|
||||
|
@ -2971,6 +3514,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
}
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
SqmPath result = attribute.getElementPathSource().createSqmPath(
|
||||
pluralAttributePath,
|
||||
this
|
||||
|
|
|
@ -69,9 +69,11 @@ import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFormat;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmFunction;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteral;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter;
|
||||
|
@ -125,6 +127,7 @@ import org.hibernate.sql.ast.tree.expression.CastTarget;
|
|||
import org.hibernate.sql.ast.tree.expression.Distinct;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.ExtractUnit;
|
||||
import org.hibernate.sql.ast.tree.expression.Format;
|
||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||
import org.hibernate.sql.ast.tree.expression.Star;
|
||||
import org.hibernate.sql.ast.tree.expression.TrimSpecification;
|
||||
|
@ -781,6 +784,10 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
|
||||
@Override
|
||||
public Expression visitLiteral(SqmLiteral literal) {
|
||||
if ( literal instanceof SqmLiteralNull ) {
|
||||
return new QueryLiteral( null, (BasicValuedMapping) inferableTypeAccessStack.getCurrent().get() );
|
||||
}
|
||||
|
||||
return new QueryLiteral(
|
||||
literal.getLiteralValue(),
|
||||
(BasicValuedMapping) SqmMappingModelHelper.resolveMappingModelExpressable(
|
||||
|
@ -939,13 +946,11 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
|
||||
@Override
|
||||
public Expression visitFunction(SqmFunction sqmFunction) {
|
||||
final SqmFunctionDescriptor functionDescriptor = creationContext.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getSqmFunctionRegistry()
|
||||
.getFunctionDescriptor( sqmFunction.getFunctionName() );
|
||||
final SqmFunctionDescriptor functionDescriptor = sqmFunction.getFunctionDescriptor();
|
||||
|
||||
shallownessStack.push( Shallowness.FUNCTION );
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return functionDescriptor.generateSqlExpression(
|
||||
sqmFunction.getFunctionName(),
|
||||
sqmFunction.getArguments(),
|
||||
|
@ -1009,6 +1014,14 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitFormat(SqmFormat sqmFormat) {
|
||||
return new Format(
|
||||
sqmFormat.getLiteralValue(),
|
||||
(BasicValuedMapping) sqmFormat.getNodeType()
|
||||
);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public Object visitAbsFunction(SqmAbsFunction function) {
|
||||
// shallownessStack.push( Shallowness.FUNCTION );
|
||||
|
@ -1425,7 +1438,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
return new BinaryArithmeticExpression(
|
||||
(Expression) expression.getLeftHandOperand().accept( this ), interpret( expression.getOperator() ),
|
||||
(Expression) expression.getRightHandOperand().accept( this ),
|
||||
determineValueMapping( expression )
|
||||
(BasicValuedMapping) determineValueMapping( expression )
|
||||
);
|
||||
}
|
||||
finally {
|
||||
|
|
|
@ -13,13 +13,13 @@ import java.util.function.Consumer;
|
|||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression;
|
||||
|
@ -100,13 +100,11 @@ public class BasicValuedPathInterpretation<T> implements AssignableSqmPathInterp
|
|||
|
||||
assert tableGroup != null;
|
||||
this.tableGroup = tableGroup;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath<T> getInterpretedSqmPath() {
|
||||
return sqmPath;
|
||||
public NavigablePath getNavigablePath() {
|
||||
return sqmPath.getNavigablePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.function.Consumer;
|
|||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||
|
@ -78,8 +79,8 @@ public class EmbeddableValuedPathInterpretation<T> implements AssignableSqmPathI
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPath<T> getInterpretedSqmPath() {
|
||||
return sqmPath;
|
||||
public NavigablePath getNavigablePath() {
|
||||
return sqmPath.getNavigablePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.query.sqm.sql.internal;
|
|||
|
||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
|
@ -62,13 +63,13 @@ public class EntityValuedPathInterpretation<T> implements SqmPathInterpretation<
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPath<T> getInterpretedSqmPath() {
|
||||
return sqmPath;
|
||||
public NavigablePath getNavigablePath() {
|
||||
return sqmPath.getNavigablePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return null;
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,16 +16,11 @@ import org.hibernate.sql.ast.tree.expression.Expression;
|
|||
* for path interpretations because it can (and likely) contains multiple SqlExpressions (entity to its columns, e.g.)
|
||||
*
|
||||
* @see org.hibernate.query.sqm.sql.SqmToSqlAstConverter
|
||||
* @see #getInterpretedSqmPath
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqmPathInterpretation<T> extends Expression, DomainResultProducer<T> {
|
||||
default NavigablePath getNavigablePath() {
|
||||
return getInterpretedSqmPath().getNavigablePath();
|
||||
}
|
||||
|
||||
SqmPath<T> getInterpretedSqmPath();
|
||||
NavigablePath getNavigablePath();
|
||||
|
||||
@Override
|
||||
ModelPart getExpressionType();
|
||||
|
|
|
@ -55,6 +55,10 @@ public class SqmFunction<T> extends AbstractSqmExpression<T> implements JpaFunct
|
|||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public SqmFunctionDescriptor getFunctionDescriptor() {
|
||||
return functionDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFunctionName() {
|
||||
return functionName;
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.query.sqm.tree.expression;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmSelfRenderingExpression<T> extends AbstractSqmExpression<T> implements SqmExpression<T> {
|
||||
private final Function<SemanticQueryWalker, Expression> renderer;
|
||||
|
||||
public SqmSelfRenderingExpression(
|
||||
Function<SemanticQueryWalker, Expression> renderer,
|
||||
SqmExpressable<T> type,
|
||||
NodeBuilder criteriaBuilder) {
|
||||
super( type, criteriaBuilder );
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X accept(SemanticQueryWalker<X> walker) {
|
||||
//noinspection unchecked
|
||||
return (X) renderer.apply( walker );
|
||||
}
|
||||
}
|
|
@ -23,6 +23,8 @@ public class SqmSelection<T> extends AbstractSqmNode implements SqmAliasedNode<T
|
|||
SqmSelectableNode<T> selectableNode,
|
||||
NodeBuilder nodeBuilder) {
|
||||
super( nodeBuilder );
|
||||
|
||||
assert selectableNode != null;
|
||||
this.selectableNode = selectableNode;
|
||||
}
|
||||
|
||||
|
@ -31,6 +33,8 @@ public class SqmSelection<T> extends AbstractSqmNode implements SqmAliasedNode<T
|
|||
String alias,
|
||||
NodeBuilder nodeBuilder) {
|
||||
super( nodeBuilder );
|
||||
|
||||
assert selectableNode != null;
|
||||
this.selectableNode = selectableNode;
|
||||
selectableNode.alias( alias );
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ import org.hibernate.sql.ast.tree.select.SortSpecification;
|
|||
import org.hibernate.sql.exec.internal.JdbcParametersImpl;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
|
||||
import org.hibernate.type.descriptor.sql.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.sql.ast.spi.SqlAppender.CLOSE_PARENTHESIS;
|
||||
|
@ -803,9 +804,11 @@ public abstract class AbstractSqlAstWalker
|
|||
|
||||
@Override
|
||||
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
|
||||
appendSql( "(" );
|
||||
arithmeticExpression.getLeftHandOperand().accept( this );
|
||||
appendSql( arithmeticExpression.getOperator().getOperatorSqlTextString() );
|
||||
arithmeticExpression.getRightHandOperand().accept( this );
|
||||
appendSql( ")" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteStrategy;
|
||||
|
@ -52,6 +53,11 @@ public class CteTableGroup implements TableGroup {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TableGroupJoin> getTableGroupJoins() {
|
||||
return Collections.emptySet();
|
||||
|
|
|
@ -6,10 +6,17 @@
|
|||
*/
|
||||
package org.hibernate.sql.ast.tree.expression;
|
||||
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.query.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -20,13 +27,13 @@ public class BinaryArithmeticExpression implements Expression, DomainResultProdu
|
|||
private final BinaryArithmeticOperator operator;
|
||||
private final Expression rhsOperand;
|
||||
|
||||
private final MappingModelExpressable resultType;
|
||||
private final BasicValuedMapping resultType;
|
||||
|
||||
public BinaryArithmeticExpression(
|
||||
Expression lhsOperand,
|
||||
BinaryArithmeticOperator operator,
|
||||
Expression rhsOperand,
|
||||
MappingModelExpressable resultType) {
|
||||
BasicValuedMapping resultType) {
|
||||
this.operator = operator;
|
||||
this.lhsOperand = lhsOperand;
|
||||
this.rhsOperand = rhsOperand;
|
||||
|
@ -34,7 +41,7 @@ public class BinaryArithmeticExpression implements Expression, DomainResultProdu
|
|||
}
|
||||
|
||||
@Override
|
||||
public MappingModelExpressable getExpressionType() {
|
||||
public BasicValuedMapping getExpressionType() {
|
||||
return resultType;
|
||||
}
|
||||
|
||||
|
@ -43,22 +50,37 @@ public class BinaryArithmeticExpression implements Expression, DomainResultProdu
|
|||
walker.visitBinaryArithmeticExpression( this );
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public DomainResult createDomainResult(
|
||||
// String resultVariable,
|
||||
// DomainResultCreationState creationState) {
|
||||
// final SqlSelection sqlSelection = creationState.getSqlExpressionResolver().resolveSqlSelection(
|
||||
// this,
|
||||
// getType().getJavaTypeDescriptor(),
|
||||
// creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
// );
|
||||
// //noinspection unchecked
|
||||
// return new ScalarDomainResultImpl(
|
||||
// sqlSelection.getValuesArrayPosition(),
|
||||
// resultVariable,
|
||||
// resultType.getJavaTypeDescriptor()
|
||||
// );
|
||||
// }
|
||||
@Override
|
||||
public DomainResult createDomainResult(
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlSelection sqlSelection = creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
|
||||
this,
|
||||
resultType.getBasicType().getJavaTypeDescriptor(),
|
||||
creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
);
|
||||
|
||||
//noinspection unchecked
|
||||
return new BasicResult(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
resultVariable,
|
||||
resultType.getBasicType().getJavaTypeDescriptor()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlSelection createSqlSelection(
|
||||
int jdbcPosition,
|
||||
int valuesArrayPosition,
|
||||
JavaTypeDescriptor javaTypeDescriptor,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
return new SqlSelectionImpl(
|
||||
jdbcPosition,
|
||||
valuesArrayPosition,
|
||||
this,
|
||||
resultType.getJdbcMapping()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the left-hand operand.
|
||||
|
|
|
@ -9,11 +9,11 @@ package org.hibernate.sql.ast.tree.from;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||
|
||||
|
@ -21,7 +21,6 @@ import org.hibernate.sql.ast.spi.SqlAliasBase;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifier implements TableGroup {
|
||||
|
||||
private final NavigablePath navigablePath;
|
||||
private final TableGroupProducer producer;
|
||||
private final LockMode lockMode;
|
||||
|
@ -78,6 +77,11 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
|||
return producer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockMode getLockMode() {
|
||||
return lockMode;
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.function.Supplier;
|
|||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
|
||||
|
@ -43,6 +44,11 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
|||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableValuedModelPart getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
// none, although we could also delegate to the underlyingTableGroup's group-alias
|
||||
|
@ -50,7 +56,7 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
public EmbeddableValuedModelPart getModelPart() {
|
||||
return compositionMapping;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
|
||||
|
@ -41,6 +42,11 @@ public class MutatingTableReferenceGroupWrapper implements VirtualTableGroup {
|
|||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return null;
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
|
@ -26,7 +27,7 @@ import org.hibernate.sql.results.graph.DomainResultCreationState;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, DomainResultProducer {
|
||||
public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, SqmPathInterpretation, DomainResultProducer {
|
||||
NavigablePath getNavigablePath();
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
|
@ -40,6 +41,11 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return null;
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
|
@ -42,6 +43,11 @@ public class EntityCollectionPartTableGroup implements TableGroup {
|
|||
return collectionPartPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getExpressionType() {
|
||||
return getModelPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return null;
|
||||
|
|
|
@ -7,10 +7,16 @@
|
|||
package org.hibernate.type.descriptor;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalQueries;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
|
@ -61,6 +67,16 @@ public final class DateTimeUtils {
|
|||
.optionalStart().appendZoneOrOffsetId().optionalEnd()
|
||||
.toFormatter();
|
||||
|
||||
/**
|
||||
* Pattern used for parsing literal dates in HQL.
|
||||
*/
|
||||
public static final DateTimeFormatter DATE = ISO_LOCAL_DATE;
|
||||
|
||||
/**
|
||||
* Pattern used for parsing literal times in HQL.
|
||||
*/
|
||||
public static final DateTimeFormatter TIME = ISO_LOCAL_TIME;
|
||||
|
||||
/**
|
||||
* Pattern used for parsing literal offset datetimes in HQL.
|
||||
*
|
||||
|
@ -170,4 +186,79 @@ public final class DateTimeUtils {
|
|||
return formatter;
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
final ZoneId localTzId = ZoneId.systemDefault();
|
||||
System.out.printf( "Local tz : %s\n", localTzId );
|
||||
|
||||
final String[] values = new String[] {
|
||||
"1999-12-31 12:59:59.3",
|
||||
"1999-12-31 12:59:59 +02:00",
|
||||
"1999-12-31 12:59:59 UTC",
|
||||
"1999-12-31 12:59:59 UTC+02:00",
|
||||
"1999-12-31 12:59:59 " + localTzId.getId()
|
||||
};
|
||||
|
||||
for ( String value : values ) {
|
||||
final TemporalAccessor parsed = DATE_TIME.parseBest(
|
||||
value,
|
||||
OffsetDateTime::from,
|
||||
ZonedDateTime::from,
|
||||
LocalDateTime::from
|
||||
);
|
||||
|
||||
System.out.println( value + " -> " + parsed + " (" + parsed.getClass().getName() + ")" );
|
||||
|
||||
final ZonedDateTime zdt;
|
||||
|
||||
if ( parsed instanceof LocalDateTime ) {
|
||||
// here, "localTzId" would come from the "jdbc timezone" setting?
|
||||
zdt = ( (LocalDateTime) parsed ).atZone( localTzId );
|
||||
System.out.println( " - LocalDateTime adjusted to ZonedDateTime : " + parsed );
|
||||
}
|
||||
else if ( parsed instanceof OffsetDateTime ) {
|
||||
zdt = ( (OffsetDateTime) parsed ).toZonedDateTime();
|
||||
System.out.println( " - OffsetDateTime adjusted to ZonedDateTime : " + parsed );
|
||||
}
|
||||
else {
|
||||
zdt = (ZonedDateTime) parsed;
|
||||
}
|
||||
|
||||
System.out.println( " - ZoneId = " + zdt.getZone().getId() );
|
||||
System.out.println( " - offset = " + zdt.getOffset() );
|
||||
System.out.println( " - normalized = " + zdt.getZone().normalized() );
|
||||
|
||||
final ZonedDateTime adjusted = zdt.withZoneSameInstant( localTzId );
|
||||
System.out.println( " - adjusted = " + adjusted.toLocalDateTime() + " (zone-id:" + adjusted.getZone() + ")" );
|
||||
}
|
||||
}
|
||||
|
||||
public static TemporalAccessor transform(String text) {
|
||||
return DATE_TIME.parse(
|
||||
text,
|
||||
(temporal) -> {
|
||||
// see if there is an offset or tz
|
||||
final ZoneId zoneOrOffset = temporal.query( TemporalQueries.zone() );
|
||||
if ( zoneOrOffset != null ) {
|
||||
final ZonedDateTime zdt = ZonedDateTime.from( temporal );
|
||||
// EDIT: call normalized() to convert a ZoneId
|
||||
// with constant offset, e.g., UTC+02:00, to ZoneOffset
|
||||
if ( zoneOrOffset.normalized() instanceof ZoneOffset ) {
|
||||
return zdt.toOffsetDateTime();
|
||||
}
|
||||
else {
|
||||
return zdt;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise it's a LocalDateTime
|
||||
return LocalDateTime.from( temporal );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static OffsetDateTime usingOffset(String text) {
|
||||
// does not work
|
||||
final TemporalAccessor parsed = DATE_TIME.parse( text );
|
||||
return OffsetDateTime.from( parsed );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,10 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterNumericData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#BIGINT BIGINT} handling.
|
||||
|
@ -38,6 +41,17 @@ public class BigIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Long.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
//noinspection unchecked
|
||||
return new JdbcLiteralFormatterNumericData( javaTypeDescriptor, Long.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -15,7 +15,9 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#BIT BIT} handling.
|
||||
|
@ -40,6 +42,11 @@ public class BitTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Boolean.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -16,7 +16,9 @@ import java.sql.Types;
|
|||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#BLOB BLOB} handling.
|
||||
|
@ -40,6 +42,11 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Blob.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -15,7 +15,10 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterBoolean;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link java.sql.Types#BOOLEAN BOOLEAN} handling.
|
||||
|
@ -37,6 +40,17 @@ public class BooleanTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Boolean.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
//noinspection unchecked
|
||||
return new JdbcLiteralFormatterBoolean( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
|
|
|
@ -14,10 +14,15 @@ import java.sql.SQLException;
|
|||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterTemporal;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#DATE DATE} handling.
|
||||
|
@ -40,6 +45,17 @@ public class DateTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Date.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return new JdbcLiteralFormatterTemporal( javaTypeDescriptor, TemporalType.DATE );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -16,7 +16,10 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterNumericData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#DECIMAL DECIMAL} handling.
|
||||
|
@ -39,6 +42,17 @@ public class DecimalTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( BigDecimal.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
//noinspection unchecked
|
||||
return new JdbcLiteralFormatterNumericData( javaTypeDescriptor, BigDecimal.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -15,7 +15,10 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterNumericData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#DOUBLE DOUBLE} handling.
|
||||
|
@ -38,6 +41,17 @@ public class DoubleTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Double.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
//noinspection unchecked
|
||||
return new JdbcLiteralFormatterNumericData( javaTypeDescriptor, Double.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -8,6 +8,9 @@ package org.hibernate.type.descriptor.sql;
|
|||
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#FLOAT FLOAT} handling.
|
||||
*
|
||||
|
@ -19,6 +22,11 @@ public class FloatTypeDescriptor extends RealTypeDescriptor {
|
|||
public FloatTypeDescriptor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Double.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.FLOAT;
|
||||
|
|
|
@ -15,7 +15,10 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterNumericData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#INTEGER INTEGER} handling.
|
||||
|
@ -38,6 +41,17 @@ public class IntegerTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Integer.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return new JdbcLiteralFormatterNumericData( javaTypeDescriptor, Integer.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 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.sql.ast.spi;
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|
@ -12,13 +12,15 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.sql.ast.spi.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterCharacterData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.sql.ast.spi.JdbcLiteralFormatter.NULL;
|
||||
import static org.hibernate.type.descriptor.sql.JdbcLiteralFormatter.NULL;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#NVARCHAR NVARCHAR} handling.
|
||||
|
@ -41,9 +43,15 @@ public class NVarcharTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( String.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return (value, dialect, session) -> value == null ? NULL : "'" + value.toString() + "'";
|
||||
//noinspection unchecked
|
||||
return new JdbcLiteralFormatterCharacterData( javaTypeDescriptor, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,7 +15,10 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterNumericData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#REAL REAL} handling.
|
||||
|
@ -38,6 +41,17 @@ public class RealTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Float.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return new JdbcLiteralFormatterNumericData( javaTypeDescriptor, Float.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -15,7 +15,10 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterNumericData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#SMALLINT SMALLINT} handling.
|
||||
|
@ -38,6 +41,17 @@ public class SmallIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Short.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return new JdbcLiteralFormatterNumericData( javaTypeDescriptor, Short.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.hibernate.type.descriptor.sql;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.sql.ast.spi.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
|
|
|
@ -14,10 +14,15 @@ import java.sql.Time;
|
|||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterTemporal;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#TIME TIME} handling.
|
||||
|
@ -40,6 +45,17 @@ public class TimeTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Time.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return new JdbcLiteralFormatterTemporal( javaTypeDescriptor, TemporalType.TIME );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -14,10 +14,15 @@ import java.sql.Timestamp;
|
|||
import java.sql.Types;
|
||||
import java.util.Calendar;
|
||||
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterTemporal;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#TIMESTAMP TIMESTAMP} handling.
|
||||
|
@ -40,6 +45,17 @@ public class TimestampTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Timestamp.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return new JdbcLiteralFormatterTemporal( javaTypeDescriptor, TemporalType.TIMESTAMP );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -15,7 +15,10 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterNumericData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#TINYINT TINYINT} handling.
|
||||
|
@ -41,6 +44,17 @@ public class TinyIntTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Short.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return new JdbcLiteralFormatterNumericData( javaTypeDescriptor, Short.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
|
|
@ -15,7 +15,9 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#VARBINARY VARBINARY} handling.
|
||||
|
@ -37,6 +39,11 @@ public class VarbinaryTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( byte[].class );
|
||||
}
|
||||
|
||||
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
|
||||
return new BasicBinder<X>( javaTypeDescriptor, this ) {
|
||||
|
||||
|
|
|
@ -12,13 +12,13 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.sql.ast.spi.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
import static org.hibernate.sql.ast.spi.JdbcLiteralFormatter.NULL;
|
||||
import org.hibernate.type.descriptor.sql.internal.JdbcLiteralFormatterCharacterData;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Descriptor for {@link Types#VARCHAR VARCHAR} handling.
|
||||
|
@ -41,9 +41,15 @@ public class VarcharTypeDescriptor implements SqlTypeDescriptor {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
|
||||
return (BasicJavaDescriptor<T>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( String.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
|
||||
return (value, dialect, session) -> value == null ? NULL : "'" + value.toString() + "'";
|
||||
//noinspection unchecked
|
||||
return new JdbcLiteralFormatterCharacterData( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.type.descriptor.sql.internal;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.spi.BasicJdbcLiteralFormatter;
|
||||
|
||||
/**
|
||||
* JdbcLiteralFormatter implementation for handling boolean literals
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcLiteralFormatterBoolean extends BasicJdbcLiteralFormatter {
|
||||
public JdbcLiteralFormatterBoolean(JavaTypeDescriptor javaTypeDescriptor) {
|
||||
super( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJdbcLiteral(Object value, Dialect dialect, SharedSessionContractImplementor session) {
|
||||
return unwrap( value, Boolean.class, session ).toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.type.descriptor.sql.internal;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.spi.BasicJdbcLiteralFormatter;
|
||||
|
||||
/**
|
||||
* JdbcLiteralFormatter implementation for handling character data
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcLiteralFormatterCharacterData extends BasicJdbcLiteralFormatter {
|
||||
private final boolean isNationalized;
|
||||
|
||||
public JdbcLiteralFormatterCharacterData(JavaTypeDescriptor javaTypeDescriptor) {
|
||||
this( javaTypeDescriptor, false );
|
||||
}
|
||||
|
||||
public JdbcLiteralFormatterCharacterData(JavaTypeDescriptor javaTypeDescriptor, boolean isNationalized) {
|
||||
super( javaTypeDescriptor );
|
||||
this.isNationalized = isNationalized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJdbcLiteral(Object value, Dialect dialect, SharedSessionContractImplementor session) {
|
||||
final String literalValue = unwrap( value, String.class, session );
|
||||
|
||||
if ( isNationalized ) {
|
||||
// is there a standardized form for n-string literals? This is the SQL Server syntax for sure
|
||||
return String.format( Locale.ROOT, "n'%s'", literalValue );
|
||||
}
|
||||
else {
|
||||
return String.format( Locale.ROOT, "'%s'", literalValue );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.type.descriptor.sql.internal;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.spi.BasicJdbcLiteralFormatter;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcLiteralFormatterNumericData extends BasicJdbcLiteralFormatter {
|
||||
private final Class<? extends Number> unwrapJavaType;
|
||||
|
||||
public JdbcLiteralFormatterNumericData(
|
||||
JavaTypeDescriptor javaTypeDescriptor,
|
||||
Class<? extends Number> unwrapJavaType) {
|
||||
super( javaTypeDescriptor );
|
||||
this.unwrapJavaType = unwrapJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJdbcLiteral(Object value, Dialect dialect, SharedSessionContractImplementor session) {
|
||||
return unwrap( value, unwrapJavaType, session ).toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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.type.descriptor.sql.internal;
|
||||
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.spi.BasicJdbcLiteralFormatter;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcLiteralFormatterTemporal extends BasicJdbcLiteralFormatter {
|
||||
private final TemporalType precision;
|
||||
|
||||
public JdbcLiteralFormatterTemporal(JavaTypeDescriptor javaTypeDescriptor, TemporalType precision) {
|
||||
super( javaTypeDescriptor );
|
||||
this.precision = precision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJdbcLiteral(Object value, Dialect dialect, SharedSessionContractImplementor session) {
|
||||
// for performance reasons, avoid conversions if we can
|
||||
if ( value instanceof java.util.Date ) {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
(java.util.Date) value,
|
||||
precision
|
||||
);
|
||||
}
|
||||
else if ( value instanceof java.util.Calendar ) {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
(java.util.Calendar) value,
|
||||
precision
|
||||
);
|
||||
}
|
||||
else if ( value instanceof TemporalAccessor ) {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
(TemporalAccessor) value,
|
||||
precision
|
||||
);
|
||||
}
|
||||
|
||||
switch ( precision) {
|
||||
case DATE: {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
unwrap( value, java.sql.Date.class, session ),
|
||||
precision
|
||||
);
|
||||
}
|
||||
case TIME: {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
unwrap( value, java.sql.Time.class, session ),
|
||||
precision
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return dialect.formatDateTimeLiteral(
|
||||
unwrap( value, java.util.Date.class, session ),
|
||||
precision
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.type.descriptor.sql.spi;
|
||||
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.JdbcLiteralFormatter;
|
||||
|
||||
/**
|
||||
* Abstract JdbcLiteralFormatter implementation managing the JavaTypeDescriptor
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractJdbcLiteralFormatter implements JdbcLiteralFormatter {
|
||||
private final JavaTypeDescriptor javaTypeDescriptor;
|
||||
|
||||
public AbstractJdbcLiteralFormatter(JavaTypeDescriptor javaTypeDescriptor) {
|
||||
this.javaTypeDescriptor = javaTypeDescriptor;
|
||||
}
|
||||
|
||||
protected JavaTypeDescriptor getJavaTypeDescriptor() {
|
||||
return javaTypeDescriptor;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.type.descriptor.sql.spi;
|
||||
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* Support for JdbcLiteralFormatter implementations with a basic implementation of an unwrap method
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class BasicJdbcLiteralFormatter extends AbstractJdbcLiteralFormatter {
|
||||
public BasicJdbcLiteralFormatter(JavaTypeDescriptor<?> javaTypeDescriptor) {
|
||||
super( javaTypeDescriptor );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <X> X unwrap(Object value, Class<X> unwrapType, SharedSessionContractImplementor session) {
|
||||
assert value != null;
|
||||
|
||||
// for performance reasons, avoid conversions if we can
|
||||
if ( unwrapType.isInstance( value ) ) {
|
||||
return (X) value;
|
||||
}
|
||||
|
||||
return (X) getJavaTypeDescriptor().unwrap( value, unwrapType, session );
|
||||
}
|
||||
}
|
|
@ -6,35 +6,92 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.query.hql;
|
||||
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.orm.test.query.sqm.BaseSqmUnitTest;
|
||||
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
||||
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LiteralTests extends BaseSqmUnitTest {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@ServiceRegistry
|
||||
@DomainModel( standardModels = StandardDomainModel.GAMBIT )
|
||||
@SessionFactory
|
||||
public class LiteralTests {
|
||||
|
||||
@Override
|
||||
protected void applyMetadataSources(MetadataSources metadataSources) {
|
||||
StandardDomainModel.GAMBIT.getDescriptor().applyDomainModel( metadataSources );
|
||||
@Test
|
||||
public void testJdbcTimeLiteral(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theTime = {t 12:30:00}" ).list();
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theTime = {t '12:30:00'}" ).list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimestampLiteral() {
|
||||
final SqmSelectStatement sqm = interpretSelect( "from EntityOfBasics e1 where e1.theTimestamp = {ts '2018-01-01T12:30:00'}" );
|
||||
public void testJdbcDateLiteral(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theDate = {d 1999-12-31}" ).list();
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theDate = {d '1999-12-31'}" ).list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateLiteral() {
|
||||
final SqmSelectStatement sqm = interpretSelect( "from EntityOfBasics e1 where e1.theDate = {d '2018-01-01'}" );
|
||||
public void testJdbcTimestampLiteral(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theDate = {ts 1999-12-31 12:30:00}" ).list();
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theDate = {ts '1999-12-31 12:30:00'}" ).list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeLiteral() {
|
||||
final SqmSelectStatement sqm = interpretSelect( "from EntityOfBasics e1 where e1.theTime = {t '12:30:00'}" );
|
||||
public void testLocalDateLiteral(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theLocalDate = {1999-12-31}" ).list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalTimeLiteral(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theLocalTime = {12:59:59}" ).list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeLiteral(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
// todo (6.0) : removed this difference between the string-literal form and the date-time-field form (with/without 'T')
|
||||
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theLocalDateTime = {1999-12-31 12:59:59}" ).list();
|
||||
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theZonedDateTime = {1999-12-31 12:59:59 +01:00}" ).list();
|
||||
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theZonedDateTime = {1999-12-31 12:59:59 CST}" ).list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isolated(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theLocalDateTime = {1999-12-31 12:59:59}" ).list();
|
||||
session.createQuery( "from EntityOfBasics e1 where e1.theZonedDateTime = {1999-12-31 12:59:59 +01:00}" ).list();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,6 @@ public class StandardFunctionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected
|
||||
public void testCoalesceFunction(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -617,120 +616,176 @@ public class StandardFunctionTests {
|
|||
public void isolated(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select extract(time from local_datetime), extract(date from local_datetime) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select extract(time from e.theTimestamp), extract(date from e.theTimestamp) from EntityOfBasics e").list();
|
||||
session.createQuery("select extract(time from local_datetime), extract(date from local_datetime) from EntityOfBasics e").list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected
|
||||
// @FailureExpected
|
||||
public void testExtractFunctionWithAssertions(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
EntityOfBasics entity = new EntityOfBasics();
|
||||
entity.setId(1);
|
||||
session.save(entity);
|
||||
session.flush();
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertThat(
|
||||
session.createQuery("select extract(week of year from date '2019-01-01') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(week of year from {2019-01-01}) from EntityOfBasics b where b.id = 1" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 1 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(week of year from date '2019-01-05') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(week of year from {2019-01-01}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 1 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(week of year from date '2019-01-06') from EntityOfBasics").getResultList().get(0),
|
||||
is(2)
|
||||
session.createQuery(
|
||||
"select extract(week of year from {2019-01-01}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 1 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery(
|
||||
"select extract(week of year from {2019-01-01}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 1 )
|
||||
);
|
||||
|
||||
assertThat(
|
||||
session.createQuery("select extract(week of month from date '2019-05-01') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(week of year from {2019-01-05}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 1 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(week of month from date '2019-05-04') from EntityOfBasics").getResultList().get(0),
|
||||
is(1)
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(week of month from date '2019-05-05') from EntityOfBasics").getResultList().get(0),
|
||||
is(2)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
session.createQuery("select extract(week from date '2019-05-27') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(week of month from {2019-05-01}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 1 )
|
||||
);
|
||||
|
||||
assertThat(
|
||||
session.createQuery( "select extract(week from {2019-05-27}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 22 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(week from date '2019-06-02') from EntityOfBasics").getResultList().get(0),
|
||||
is(22)
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(week from date '2019-06-03') from EntityOfBasics").getResultList().get(0),
|
||||
is(23)
|
||||
);
|
||||
|
||||
assertThat(
|
||||
session.createQuery("select extract(day of year from date '2019-05-30') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(day of year from {2019-05-30}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 150 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(day of month from date '2019-05-27') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(day of month from {2019-05-27}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 27 )
|
||||
);
|
||||
|
||||
assertThat(
|
||||
session.createQuery("select extract(day from date '2019-05-31') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery( "select extract(day from {2019-05-31}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 31 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(month from date '2019-05-31') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery( "select extract(month from {2019-05-31}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 5 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(year from date '2019-05-31') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery( "select extract(year from {2019-05-31}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 2019 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(quarter from date '2019-05-31') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(quarter from {2019-05-31}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 2 )
|
||||
);
|
||||
|
||||
assertThat(
|
||||
session.createQuery("select extract(day of week from date '2019-05-27') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(day of week from {2019-05-27}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 2 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(day of week from date '2019-05-31') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select extract(day of week from {2019-05-31}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 6 )
|
||||
);
|
||||
|
||||
assertThat(
|
||||
session.createQuery("select extract(second from time '14:12:10') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery( "select extract(second from {14:12:10}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 10f )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(minute from time '14:12:10') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery( "select extract(minute from {14:12:10}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 12 )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(hour from time '14:12:10') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery( "select extract(hour from {14:12:10}) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( 14 )
|
||||
);
|
||||
|
||||
assertThat(
|
||||
session.createQuery("select extract(date from current datetime) from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery( "select extract(date from local_datetime) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
instanceOf( LocalDate.class )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select extract(time from current datetime) from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery( "select extract(time from local_datetime) from EntityOfBasics" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
instanceOf( LocalTime.class )
|
||||
);
|
||||
session.delete(entity);
|
||||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from EntityOfBasics" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtractFunctions(SessionFactoryScope scope) {
|
||||
|
@ -795,14 +850,8 @@ public class StandardFunctionTests {
|
|||
public void testCountFunction(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery("select count(*) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select count(1) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select count(e) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select count(distinct e) from EntityOfBasics e")
|
||||
.list();
|
||||
session.createQuery("select count(e) from EntityOfBasics e").list();
|
||||
session.createQuery("select count(distinct e) from EntityOfBasics e").list();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -820,7 +869,6 @@ public class StandardFunctionTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected
|
||||
public void testFormat(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -830,24 +878,44 @@ public class StandardFunctionTests {
|
|||
entity.setTheTime( new Time( 23, 10, 8 ) );
|
||||
entity.setTheTimestamp( new Timestamp( System.currentTimeMillis() ) );
|
||||
session.persist( entity );
|
||||
session.flush();
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "select format(e.theTime as 'hh:mm:ss aa') from EntityOfBasics e" )
|
||||
.list();
|
||||
session.createQuery("select format(e.theDate as 'dd/MM/yy'), format(e.theDate as 'EEEE, MMMM dd, yyyy') from EntityOfBasics e")
|
||||
session.createQuery(
|
||||
"select format(e.theDate as 'dd/MM/yy'), format(e.theDate as 'EEEE, MMMM dd, yyyy') from EntityOfBasics e" )
|
||||
.list();
|
||||
session.createQuery("select format(e.theTimestamp as 'dd/MM/yyyy ''at'' HH:mm:ss') from EntityOfBasics e")
|
||||
session.createQuery(
|
||||
"select format(e.theTimestamp as 'dd/MM/yyyy ''at'' HH:mm:ss') from EntityOfBasics e" )
|
||||
.list();
|
||||
|
||||
assertThat(
|
||||
session.createQuery("select format(e.theDate as 'EEEE, dd/MM/yyyy') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select format(e.theDate as 'EEEE, dd/MM/yyyy') from EntityOfBasics e" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( "Monday, 25/03/1974" )
|
||||
);
|
||||
assertThat(
|
||||
session.createQuery("select format(e.theTime as '''Hello'', hh:mm:ss aa') from EntityOfBasics").getResultList().get(0),
|
||||
session.createQuery(
|
||||
"select format(e.theTime as '''Hello'', hh:mm:ss aa') from EntityOfBasics e" )
|
||||
.getResultList()
|
||||
.get( 0 ),
|
||||
is( "Hello, 11:10:08 PM" )
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
finally {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete EntityOfBasics" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,11 @@ package org.hibernate.testing.orm.domain.gambit;
|
|||
import java.net.URL;
|
||||
import java.sql.Clob;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Date;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Column;
|
||||
|
@ -42,6 +47,11 @@ public class EntityOfBasics {
|
|||
private Date theTime;
|
||||
private Date theTimestamp;
|
||||
private Instant theInstant;
|
||||
private LocalDateTime theLocalDateTime;
|
||||
private LocalDate theLocalDate;
|
||||
private LocalTime theLocalTime;
|
||||
private OffsetDateTime theOffsetDateTime;
|
||||
private ZonedDateTime theZonedDateTime;
|
||||
private Gender gender;
|
||||
private Gender convertedGender;
|
||||
private Gender ordinalGender;
|
||||
|
@ -167,6 +177,46 @@ public class EntityOfBasics {
|
|||
this.theInstant = theInstant;
|
||||
}
|
||||
|
||||
public LocalDateTime getTheLocalDateTime() {
|
||||
return theLocalDateTime;
|
||||
}
|
||||
|
||||
public void setTheLocalDateTime(LocalDateTime theLocalDateTime) {
|
||||
this.theLocalDateTime = theLocalDateTime;
|
||||
}
|
||||
|
||||
public LocalDate getTheLocalDate() {
|
||||
return theLocalDate;
|
||||
}
|
||||
|
||||
public void setTheLocalDate(LocalDate theLocalDate) {
|
||||
this.theLocalDate = theLocalDate;
|
||||
}
|
||||
|
||||
public LocalTime getTheLocalTime() {
|
||||
return theLocalTime;
|
||||
}
|
||||
|
||||
public void setTheLocalTime(LocalTime theLocalTime) {
|
||||
this.theLocalTime = theLocalTime;
|
||||
}
|
||||
|
||||
public OffsetDateTime getTheOffsetDateTime() {
|
||||
return theOffsetDateTime;
|
||||
}
|
||||
|
||||
public void setTheOffsetDateTime(OffsetDateTime theOffsetDateTime) {
|
||||
this.theOffsetDateTime = theOffsetDateTime;
|
||||
}
|
||||
|
||||
public ZonedDateTime getTheZonedDateTime() {
|
||||
return theZonedDateTime;
|
||||
}
|
||||
|
||||
public void setTheZonedDateTime(ZonedDateTime theZonedDateTime) {
|
||||
this.theZonedDateTime = theZonedDateTime;
|
||||
}
|
||||
|
||||
public static class GenderConverter implements AttributeConverter<Gender,Character> {
|
||||
@Override
|
||||
public Character convertToDatabaseColumn(Gender attribute) {
|
||||
|
|
Loading…
Reference in New Issue