HHH-14642, HHH-13717 Various JPA Criteria related fixes

* Get rid of unnecessary whitespace and optional keywords in generated SQL
* Handle some type inference related issues with some databases requiring to render casted parameters in some situations
* Ensure SQM model is fully serializable
* Ensure JPA Criteria throws expected exceptions
* Make sure JPA Criteria implementations work properly
* Move jpa.test.callback and jpa.test.criteria packages
* Improve the reuse of SqmPath instances
* Get rid of many raw-types related warnings
* Make Predicate extend Expression and handle SQL rendering/emulation
* Support fetching SqmTuple as array
* Implement treat operator support
This commit is contained in:
Christian Beikov 2021-09-07 01:12:18 +02:00
parent a216a23ae4
commit 77c1370e45
332 changed files with 4957 additions and 3227 deletions

View File

@ -2,7 +2,7 @@
mysql_5_7() {
docker rm -f mysql || true
docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_cs
docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_bin
# Give the container some time to start
OUTPUT=
n=0

View File

@ -27,8 +27,8 @@ import org.hibernate.Session;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.Oracle8iDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
@ -1355,7 +1355,8 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
});
}
@Test @RequiresDialect(H2Dialect.class)
@Test
@RequiresDialect(H2Dialect.class)
public void test_hql_current_time_function_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::hql-current-time-function-example[]
@ -1385,8 +1386,8 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
@Test
@RequiresDialect(H2Dialect.class)
@RequiresDialect(Oracle8iDialect.class)
@RequiresDialect(MySQL5Dialect.class)
@RequiresDialect(OracleDialect.class)
@RequiresDialect(MySQLDialect.class)
public void test_hql_bit_length_function_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::hql-bit-length-function-example[]
@ -1940,7 +1941,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
@Test
@RequiresDialect(H2Dialect.class)
@RequiresDialect(PostgreSQLDialect.class)
@RequiresDialect(MySQL5Dialect.class)
@RequiresDialect(MySQLDialect.class)
public void test_hql_relational_comparisons_example_3() {
doInJPA( this::entityManagerFactory, entityManager -> {
@ -2145,7 +2146,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
@Test
@RequiresDialect(H2Dialect.class)
@RequiresDialect(PostgreSQLDialect.class)
@RequiresDialect(MySQL5Dialect.class)
@RequiresDialect(MySQLDialect.class)
public void test_hql_between_predicate_example_2() {
doInJPA( this::entityManagerFactory, entityManager -> {
@ -2399,9 +2400,6 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
}
@Test
@RequiresDialect(H2Dialect.class)
@RequiresDialect(PostgreSQLDialect.class)
@RequiresDialect(MySQL5Dialect.class)
public void test_hql_group_by_example_3() {
doInJPA( this::entityManagerFactory, entityManager -> {
@ -2421,9 +2419,6 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
}
@Test
@RequiresDialect(H2Dialect.class)
@RequiresDialect(PostgreSQLDialect.class)
@RequiresDialect(MySQL5Dialect.class)
public void test_hql_group_by_example_4() {
doInJPA( this::entityManagerFactory, entityManager -> {

View File

@ -167,6 +167,7 @@ public class CUBRIDDialect extends Dialect {
CommonFunctionFactory.lastDay( queryEngine );
CommonFunctionFactory.weekQuarter( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.bitLength( queryEngine );
CommonFunctionFactory.md5( queryEngine );
CommonFunctionFactory.trunc( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
@ -386,11 +387,11 @@ public class CUBRIDDialect extends Dialect {
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
switch (unit) {
case NANOSECOND:
return "adddate(?3, interval (?2)/1e6 millisecond)";
return "adddate(?3,interval (?2)/1e6 millisecond)";
case NATIVE:
return "adddate(?3, interval ?2 millisecond)";
return "adddate(?3,interval ?2 millisecond)";
default:
return "adddate(?3, interval ?2 ?1)";
return "adddate(?3,interval ?2 ?1)";
}
}

View File

@ -146,9 +146,10 @@ public class CacheDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"$find(?2, ?1)",
"$find(?2, ?1, ?3)"
"$find(?2,?1)",
"$find(?2,?1,?3)"
).setArgumentListSignature("(pattern, string[, start])");
CommonFunctionFactory.bitLength_pattern( queryEngine, "($length(?1)*8)" );
useJdbcEscape(queryEngine, "sin");
useJdbcEscape(queryEngine, "cos");
@ -181,7 +182,7 @@ public class CacheDialect extends Dialect {
@Override
public String extractPattern(TemporalUnit unit) {
return "datepart(?1, ?2)";
return "datepart(?1,?2)";
}
@Override
@ -189,9 +190,9 @@ public class CacheDialect extends Dialect {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "dateadd(millisecond, (?2)/1e6, ?3)";
return "dateadd(millisecond,(?2)/1e6,?3)";
default:
return "dateadd(?1, ?2, ?3)";
return "dateadd(?1,?2,?3)";
}
}
@ -200,9 +201,9 @@ public class CacheDialect extends Dialect {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "datediff(millisecond, ?2, ?3)*1e6";
return "datediff(millisecond,?2,?3)*1e6";
default:
return "datediff(?1, ?2, ?3)";
return "datediff(?1,?2,?3)";
}
}

View File

@ -248,7 +248,7 @@ public class FirebirdDialect extends Dialect {
"locate",
StandardBasicTypes.INTEGER,
"position(?1 in ?2)",
"position(?1, ?2, ?3)"
"position(?1,?2,?3)"
).setArgumentListSignature( "(pattern, string[, start])" );
functionRegistry.namedDescriptorBuilder( "ascii_val" )
.setExactArgumentCount( 1 )
@ -593,7 +593,7 @@ public class FirebirdDialect extends Dialect {
? "select rdb$generator_name from rdb$generators"
// Note: Firebird 3 has an 'off by increment' bug (fixed in Firebird 4), see
// http://tracker.firebirdsql.org/browse/CORE-6084
: "select rdb$generator_name, rdb$initial_value, rdb$generator_increment from rdb$generators where coalesce(rdb$system_flag, 0) = 0";
: "select rdb$generator_name,rdb$initial_value,rdb$generator_increment from rdb$generators where coalesce(rdb$system_flag,0)=0";
}
@Override

View File

@ -30,6 +30,7 @@ import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
@ -50,6 +51,16 @@ public class FirebirdSqlAstTranslator<T extends JdbcOperation> extends AbstractS
super( sessionFactory, statement );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
if ( getDialect().getVersion() >= 300 ) {
booleanExpressionPredicate.getExpression().accept( this );
}
else {
super.visitBooleanExpressionPredicate( booleanExpressionPredicate );
}
}
@Override
protected String getForUpdate() {
return " with lock";

View File

@ -168,8 +168,8 @@ public class InformixDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"instr(?2, ?1)",
"instr(?2, ?1, ?3)"
"instr(?2,?1)",
"instr(?2,?1,?3)"
).setArgumentListSignature("(pattern, string[, start])");
//coalesce() and nullif() both supported since Informix 12
@ -307,7 +307,7 @@ public class InformixDialect extends Dialect {
@Override
public String getQuerySequencesString() {
return "select systables.tabname as sequence_name, syssequences.* from syssequences join systables on syssequences.tabid = systables.tabid where tabtype = 'Q'";
return "select systables.tabname as sequence_name,syssequences.* from syssequences join systables on syssequences.tabid=systables.tabid where tabtype='Q'";
}
@Override
@ -322,7 +322,7 @@ public class InformixDialect extends Dialect {
@Override
public String getFromDual() {
return "from (select 0 from systables where tabid = 1) as dual";
return "from (select 0 from systables where tabid=1) as dual";
}
@Override

View File

@ -145,7 +145,7 @@ public class InformixSqlAstTranslator<T extends JdbcOperation> extends AbstractS
@Override
protected String getFromDual() {
return " from (select 0 from systables where tabid = 1) as dual";
return " from (select 0 from systables where tabid=1) dual";
}
@Override

View File

@ -235,15 +235,16 @@ public class IngresDialect extends Dialect {
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.format_dateFormat( queryEngine );
CommonFunctionFactory.dateTrunc( queryEngine );
CommonFunctionFactory.bitLength_pattern( queryEngine, "octet_length(hex(?1))*4" );
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3)) + (?3) - 1)"
"(position(?1 in substring(?2 from ?3))+(?3)-1)"
).setArgumentListSignature("(pattern, string[, start])");
queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1', ?2)", StandardBasicTypes.INTEGER );
queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1',?2)", StandardBasicTypes.INTEGER );
CommonFunctionFactory.bitandorxornot_bitAndOrXorNot(queryEngine);
@ -290,13 +291,13 @@ public class IngresDialect extends Dialect {
@Override
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
return "timestampadd(?1, ?2, ?3)";
return "timestampadd(?1,?2,?3)";
}
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
return "timestampdiff(?1, ?2, ?3)";
return "timestampdiff(?1,?2,?3)";
}
@Override

View File

@ -151,7 +151,7 @@ public class IngresSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
@Override
protected String getFromDual() {
//this is only necessary if the query has a where clause
return " from (select 0) as dual";
return " from (select 0) dual";
}
@Override

View File

@ -139,7 +139,7 @@ public class MaxDBDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER, "index(?2, ?1)", "index(?2, ?1, ?3)"
StandardBasicTypes.INTEGER, "index(?2,?1)", "index(?2,?1,?3)"
).setArgumentListSignature("(pattern, string[, start])");
}

View File

@ -68,7 +68,7 @@ public class MaxDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
visitDecodeCaseSearchedExpression( caseSearchedExpression );
}
else {
visitAnsiCaseSearchedExpression( caseSearchedExpression );
super.visitCaseSearchedExpression( caseSearchedExpression, inSelect );
}
}

View File

@ -101,6 +101,7 @@ public class MimerSQLDialect extends Dialect {
CommonFunctionFactory.soundex( queryEngine );
CommonFunctionFactory.octetLength( queryEngine );
CommonFunctionFactory.bitLength( queryEngine );
CommonFunctionFactory.truncate( queryEngine );
CommonFunctionFactory.repeat( queryEngine );
CommonFunctionFactory.pad_repeat( queryEngine );
@ -161,7 +162,7 @@ public class MimerSQLDialect extends Dialect {
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
StringBuilder pattern = new StringBuilder();
pattern.append("cast((?3 - ?2) ");
pattern.append("cast((?3-?2) ");
switch (unit) {
case NATIVE:
case NANOSECOND:
@ -209,13 +210,13 @@ public class MimerSQLDialect extends Dialect {
switch ( unit ) {
case NATIVE:
case NANOSECOND:
return "(?3 + (?2)/1e9 * interval '1' second)";
return "(?3+(?2)/1e9*interval '1' second)";
case QUARTER:
return "(?3 + (?2) * interval '3' month)";
return "(?3+(?2)*interval '3' month)";
case WEEK:
return "(?3 + (?2) * interval '7' day)";
return "(?3+(?2)*interval '7' day)";
default:
return "(?3 + (?2) * interval '1' ?1)";
return "(?3+(?2)*interval '1' ?1)";
}
}

View File

@ -223,11 +223,11 @@ public class RDMSOS2200Dialect extends Dialect {
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
switch (unit) {
case NANOSECOND:
return "timestampadd('SQL_TSI_FRAC_SECOND', (?2)/1e3, ?3)";
return "timestampadd('SQL_TSI_FRAC_SECOND',(?2)/1e3,?3)";
case NATIVE:
return "timestampadd('SQL_TSI_FRAC_SECOND', ?2, ?3)";
return "timestampadd('SQL_TSI_FRAC_SECOND',?2,?3)";
default:
return "dateadd('?1', ?2, ?3)";
return "dateadd('?1',?2,?3)";
}
}
@ -235,11 +235,11 @@ public class RDMSOS2200Dialect extends Dialect {
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
switch (unit) {
case NANOSECOND:
return "timestampdiff('SQL_TSI_FRAC_SECOND', ?2, ?3)*1e3";
return "timestampdiff('SQL_TSI_FRAC_SECOND',?2,?3)*1e3";
case NATIVE:
return "timestampdiff('SQL_TSI_FRAC_SECOND', ?2, ?3)";
return "timestampdiff('SQL_TSI_FRAC_SECOND',?2,?3)";
default:
return "dateadd('?1', ?2, ?3)";
return "dateadd('?1',?2,?3)";
}
}
@ -325,7 +325,7 @@ public class RDMSOS2200Dialect extends Dialect {
@Override
public String getFromDual() {
return "from rdms.rdms_dummy where key_col = 1";
return "from rdms.rdms_dummy where key_col=1";
}
@Override

View File

@ -138,7 +138,7 @@ public class RDMSOS2200SqlAstTranslator<T extends JdbcOperation> extends Abstrac
@Override
protected String getFromDual() {
return " from rdms.rdms_dummy where key_col = 1";
return " from rdms.rdms_dummy where key_col=1";
}
@Override

View File

@ -126,27 +126,27 @@ public class SQLiteDialect extends Dialect {
public String extractPattern(TemporalUnit unit) {
switch ( unit ) {
case SECOND:
return "cast(strftime('%S.%f', ?2) as double)";
return "cast(strftime('%S.%f',?2) as double)";
case MINUTE:
return "strftime('%M', ?2)";
return "strftime('%M',?2)";
case HOUR:
return "strftime('%H', ?2)";
return "strftime('%H',?2)";
case DAY:
case DAY_OF_MONTH:
return "(strftime('%d', ?2)+1)";
return "(strftime('%d',?2)+1)";
case MONTH:
return "strftime('%m', ?2)";
return "strftime('%m',?2)";
case YEAR:
return "strftime('%Y', ?2)";
return "strftime('%Y',?2)";
case DAY_OF_WEEK:
return "(strftime('%w', ?2)+1)";
return "(strftime('%w',?2)+1)";
case DAY_OF_YEAR:
return "strftime('%j', ?2)";
return "strftime('%j',?2)";
case EPOCH:
return "strftime('%s', ?2)";
return "strftime('%s',?2)";
case WEEK:
// Thanks https://stackoverflow.com/questions/15082584/sqlite-return-wrong-week-number-for-2013
return "((strftime('%j', date(?2, '-3 days', 'weekday 4'))-1)/7+1)";
return "((strftime('%j',date(?2,'-3 days','weekday 4'))-1)/7+1)";
default:
return super.extractPattern(unit);
}
@ -158,13 +158,13 @@ public class SQLiteDialect extends Dialect {
switch ( unit ) {
case NANOSECOND:
case NATIVE:
return "datetime(?3, '+?2 seconds')";
return "datetime(?3,'+?2 seconds')";
case QUARTER: //quarter is not supported in interval literals
return function + "(?3, '+'||(?2*3)||' months')";
return function + "(?3,'+'||(?2*3)||' months')";
case WEEK: //week is not supported in interval literals
return function + "(?3, '+'||(?2*7)||' days')";
return function + "(?3,'+'||(?2*7)||' days')";
default:
return function + "(?3, '+?2 ?1s')";
return function + "(?3,'+?2 ?1s')";
}
}
@ -244,20 +244,20 @@ public class SQLiteDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"instr(?2, ?1)",
"instr(?2, ?1, ?3)"
"instr(?2,?1)",
"instr(?2,?1,?3)"
).setArgumentListSignature("(pattern, string[, start])");
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"lpad",
StandardBasicTypes.STRING,
"(substr(replace(hex(zeroblob(?2)), '00', ' '), 1, ?2 - length(?1))||?1)",
"(substr(replace(hex(zeroblob(?2)), '00', ?3), 1, ?2 - length(?1))||?1)"
"(substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1))||?1)",
"(substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1))||?1)"
).setArgumentListSignature("(string, length[, padding])");
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"rpad",
StandardBasicTypes.STRING,
"(?1||substr(replace(hex(zeroblob(?2)), '00', ' '), 1, ?2 - length(?1)))",
"(?1||substr(replace(hex(zeroblob(?2)), '00', ?3), 1, ?2 - length(?1)))"
"(?1||substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1)))",
"(?1||substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1)))"
).setArgumentListSignature("(string, length[, padding])");
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "strftime")
@ -269,13 +269,13 @@ public class SQLiteDialect extends Dialect {
if (!supportsMathFunctions() ) {
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder(
"floor",
"(cast(?1 as int) - (?1 < cast(?1 as int)))"
"(cast(?1 as int)-(?1<cast(?1 as int)))"
).setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 1 ) )
.setExactArgumentCount( 1 )
.register();
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder(
"ceiling",
"(cast(?1 as int) + (?1 > cast(?1 as int)))"
"(cast(?1 as int)+(?1>cast(?1 as int)))"
).setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 1 ) )
.setExactArgumentCount( 1 )
.register();
@ -288,15 +288,15 @@ public class SQLiteDialect extends Dialect {
case BOTH:
return character == ' '
? "trim(?1)"
: "trim(?1, '" + character + "')";
: "trim(?1,'" + character + "')";
case LEADING:
return character == ' '
? "ltrim(?1)"
: "ltrim(?1, '" + character + "')";
: "ltrim(?1,'" + character + "')";
case TRAILING:
return character == ' '
? "rtrim(?1)"
: "rtrim(?1, '" + character + "')";
: "rtrim(?1,'" + character + "')";
}
throw new UnsupportedOperationException( "Unsupported specification: " + specification );
}

View File

@ -7,14 +7,18 @@
package org.hibernate.community.dialect;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
@ -36,6 +40,58 @@ public class SybaseAnywhereSqlAstTranslator<T extends JdbcOperation> extends Abs
super( sessionFactory, statement );
}
// Sybase Anywhere does not allow CASE expressions where all result arms contain plain parameters.
// At least one result arm must provide some type context for inference,
// so we cast the first result arm if we encounter this condition
@Override
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression caseSearchedExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
caseSearchedExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer );
}
}
@Override
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression caseSimpleExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) {
final List<CaseSimpleExpression.WhenFragment> whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
caseSimpleExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer );
}
}
@Override
protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) {
super.renderTableReference( tableReference, lockMode );

View File

@ -178,7 +178,7 @@ public class TeradataDialect extends Dialect {
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
StringBuilder pattern = new StringBuilder();
//TODO: TOTALLY UNTESTED CODE!
pattern.append("cast((?3 - ?2) ");
pattern.append("cast((?3-?2) ");
switch (unit) {
case NANOSECOND:
case NATIVE:
@ -214,15 +214,15 @@ public class TeradataDialect extends Dialect {
//TODO: TOTALLY UNTESTED CODE!
switch ( unit ) {
case NANOSECOND:
return "(?3 + (?2)/1e9 * interval '1' second)";
return "(?3+(?2)/1e9*interval '1' second)";
case NATIVE:
return "(?3 + (?2) * interval '1' second)";
return "(?3+(?2)*interval '1' second)";
case QUARTER:
return "(?3 + (?2) * interval '3' month)";
return "(?3+(?2)*interval '3' month)";
case WEEK:
return "(?3 + (?2) * interval '7' day)";
return "(?3+(?2)*interval '7' day)";
default:
return "(?3 + (?2) * interval '1' ?1)";
return "(?3+(?2)*interval '1' ?1)";
}
}
@ -238,6 +238,7 @@ public class TeradataDialect extends Dialect {
CommonFunctionFactory.substring_substr( queryEngine );
//also natively supports ANSI-style substring()
CommonFunctionFactory.position( queryEngine );
CommonFunctionFactory.bitLength_pattern( queryEngine, "octet_length(cast(?1 as char))*4" );
queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "mod", "(?1 mod ?2)" )
.setInvariantType( StandardBasicTypes.STRING )

View File

@ -145,8 +145,8 @@ public class TimesTenDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"instr(?2, ?1)",
"instr(?2, ?1, ?3)"
"instr(?2,?1)",
"instr(?2,?1,?3)"
).setArgumentListSignature("(pattern, string[, start])");
}
@ -166,9 +166,9 @@ public class TimesTenDialect extends Dialect {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "timestampadd(sql_tsi_frac_second, ?2, ?3)";
return "timestampadd(sql_tsi_frac_second,?2,?3)";
default:
return "timestampadd(sql_tsi_?1, ?2, ?3)";
return "timestampadd(sql_tsi_?1,?2,?3)";
}
}
@ -177,9 +177,9 @@ public class TimesTenDialect extends Dialect {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "timestampdiff(sql_tsi_frac_second, ?2, ?3)";
return "timestampdiff(sql_tsi_frac_second,?2,?3)";
default:
return "timestampdiff(sql_tsi_?1, ?2, ?3)";
return "timestampdiff(sql_tsi_?1,?2,?3)";
}
}

View File

@ -30,7 +30,7 @@ public final class RDMSSequenceSupport implements SequenceSupport {
@Override
public String getFromDual() {
// The where clause was added to eliminate this statement from Brute Force Searches.
return " from rdms.rdms_dummy where key_col = 1";
return " from rdms.rdms_dummy where key_col=1";
}
@Override

View File

@ -46,6 +46,8 @@ public class InformixDialectTestCase extends BaseUnitTestCase {
ssr = new StandardServiceRegistryBuilder().build();
queryEngine = new QueryEngine(
null,
null,
jpaMetamodel,
ValueHandlingMode.BIND,
dialect.getPreferredSqlTypeCodeForBoolean(),

View File

@ -819,8 +819,8 @@ public abstract class AbstractHANADialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"locate(?2, ?1)",
"locate(?2, ?1, ?3)"
"locate(?2,?1)",
"locate(?2,?1,?3)"
).setArgumentListSignature("(pattern, string[, start])");
CommonFunctionFactory.ceiling_ceil( queryEngine );
@ -846,6 +846,7 @@ public abstract class AbstractHANADialect extends Dialect {
CommonFunctionFactory.format_toVarchar( queryEngine );
CommonFunctionFactory.currentUtcdatetimetimestamp( queryEngine );
CommonFunctionFactory.everyAny_sumCaseCase( queryEngine );
CommonFunctionFactory.bitLength_pattern( queryEngine, "length(to_binary(?1))*8" );
}
@Override
@ -1421,7 +1422,7 @@ public abstract class AbstractHANADialect extends Dialect {
conn = connectionProvider.getConnection();
try ( Statement statement = conn.createStatement() ) {
try ( ResultSet rs = statement.executeQuery(
"SELECT TOP 1 VALUE, MAP(LAYER_NAME, 'DEFAULT', 1, 'SYSTEM', 2, 'DATABASE', 3, 4) AS LAYER FROM SYS.M_INIFILE_CONTENTS WHERE FILE_NAME='indexserver.ini' AND SECTION='session' AND KEY='max_lob_prefetch_size' ORDER BY LAYER DESC" ) ) {
"SELECT TOP 1 VALUE,MAP(LAYER_NAME,'DEFAULT',1,'SYSTEM',2,'DATABASE',3,4) AS LAYER FROM SYS.M_INIFILE_CONTENTS WHERE FILE_NAME='indexserver.ini' AND SECTION='session' AND KEY='max_lob_prefetch_size' ORDER BY LAYER DESC" ) ) {
// This only works if the current user has the privilege INIFILE ADMIN
if ( rs.next() ) {
maxLobPrefetchSizeDefault = rs.getInt( 1 );
@ -1645,21 +1646,21 @@ public abstract class AbstractHANADialect extends Dialect {
case NANOSECOND:
case NATIVE:
if ( temporalType == TemporalType.TIME ) {
return "cast(add_nano100('1970-01-01 '||(?3), ?2) as time)";
return "cast(add_nano100('1970-01-01 '||(?3),?2) as time)";
}
else {
return "add_nano100(?3, ?2)";
return "add_nano100(?3,?2)";
}
case QUARTER:
return "add_months(?3, 3*?2)";
return "add_months(?3,3*?2)";
case WEEK:
return "add_days(?3, 7*?2)";
return "add_days(?3,7*?2)";
case MINUTE:
return "add_seconds(?3, 60*?2)";
return "add_seconds(?3,60*?2)";
case HOUR:
return "add_seconds(?3, 3600*?2)";
return "add_seconds(?3,3600*?2)";
default:
return "add_?1s(?3, ?2)";
return "add_?1s(?3,?2)";
}
}
@ -1672,18 +1673,18 @@ public abstract class AbstractHANADialect extends Dialect {
// return "nano100_between(cast(?3 as timestamp), cast(?2 as timestamp))";
// }
// else {
return "nano100_between(?2, ?3)";
return "nano100_between(?2,?3)";
// }
case QUARTER:
return "months_between(?2, ?3)/3";
return "months_between(?2,?3)/3";
case WEEK:
return "days_between(?2, ?3)/7";
return "days_between(?2,?3)/7";
case MINUTE:
return "seconds_between(?2, ?3)/60";
return "seconds_between(?2,?3)/60";
case HOUR:
return "seconds_between(?2, ?3)/3600";
return "seconds_between(?2,?3)/3600";
default:
return "?1s_between(?2, ?3)";
return "?1s_between(?2,?3)";
}
}

View File

@ -229,7 +229,7 @@ public class CockroachDialect extends Dialect {
@Override
public String getQuerySequencesString() {
return "select sequence_name, sequence_schema, sequence_catalog, start_value, minimum_value, maximum_value, increment from information_schema.sequences";
return "select sequence_name,sequence_schema,sequence_catalog,start_value,minimum_value,maximum_value,increment from information_schema.sequences";
}
@Override
@ -305,15 +305,15 @@ public class CockroachDialect extends Dialect {
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
switch ( unit ) {
case NANOSECOND:
return "(?3 + (?2)/1e3 * interval '1 microsecond')";
return "(?3+(?2)/1e3*interval '1 microsecond')";
case NATIVE:
return "(?3 + (?2) * interval '1 microsecond')";
return "(?3+(?2)*interval '1 microsecond')";
case QUARTER: //quarter is not supported in interval literals
return "(?3 + (?2) * interval '3 month')";
return "(?3+(?2)*interval '3 month')";
case WEEK: //week is not supported in interval literals
return "(?3 + (?2) * interval '7 day')";
return "(?3+(?2)*interval '7 day')";
default:
return "(?3 + (?2) * interval '1 ?1')";
return "(?3+(?2)*interval '1 ?1')";
}
}

View File

@ -13,6 +13,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -29,6 +30,16 @@ public class CockroachSqlAstTranslator<T extends JdbcOperation> extends Abstract
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
booleanExpressionPredicate.getExpression().accept( this );
}
@Override
protected String getForShare() {
return " for share";

View File

@ -42,8 +42,8 @@ public class DB2400V7R3Dialect extends DB2400Dialect {
@Override
public String getQuerySequencesString() {
return "select distinct sequence_name from qsys2.syssequences " +
"where ( current_schema = '*LIBL' and sequence_schema in ( select schema_name from qsys2.library_list_info ) ) " +
"or sequence_schema = current_schema";
"where current_schema='*LIBL' and sequence_schema in (select schema_name from qsys2.library_list_info) " +
"or sequence_schema=current_schema";
}
@Override
@ -53,8 +53,8 @@ public class DB2400V7R3Dialect extends DB2400Dialect {
return sql + " fetch first " + limit + " rows only";
}
//nest the main query in an outer select
return "select * from ( select inner2_.*, rownumber() over(order by order of inner2_) as rownumber_ from ( "
+ sql + " fetch first " + limit + " rows only ) as inner2_ ) as inner1_ where rownumber_ > "
return "select * from (select inner2_.*,rownumber() over(order by order of inner2_) as rownumber_ from ("
+ sql + " fetch first " + limit + " rows only) as inner2_) as inner1_ where rownumber_>"
+ offset + " order by rownumber_";
}

View File

@ -190,6 +190,7 @@ public class DB2Dialect extends Dialect {
CommonFunctionFactory.addYearsMonthsDaysHoursMinutesSeconds( queryEngine );
CommonFunctionFactory.yearsMonthsDaysHoursMinutesSecondsBetween( queryEngine );
CommonFunctionFactory.dateTrunc( queryEngine );
CommonFunctionFactory.bitLength_pattern( queryEngine, "length(?1)*8" );
queryEngine.getSqmFunctionRegistry().register( "format", new DB2FormatEmulation() );
@ -417,7 +418,7 @@ public class DB2Dialect extends Dialect {
default:
literal = "0";
}
return "nullif(" + literal + ", " + literal + ')';
return "nullif(" + literal + "," + literal + ')';
}
@Override
@ -657,7 +658,7 @@ public class DB2Dialect extends Dialect {
return String.format(
Locale.ENGLISH,
"case when %s is null then %s else %s end, %s %s",
"case when %s is null then %s else %s end,%s %s",
expression,
nullPrecedence == NullPrecedence.FIRST ? "0" : "1",
nullPrecedence == NullPrecedence.FIRST ? "1" : "0",

View File

@ -7,16 +7,20 @@
package org.hibernate.dialect;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.query.FetchClauseType;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.MutationStatement;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
@ -25,6 +29,7 @@ import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.insert.InsertStatement;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -42,6 +47,73 @@ public class DB2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAst
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
if ( getDialect().getVersion() >= 1100 ) {
booleanExpressionPredicate.getExpression().accept( this );
}
else {
super.visitBooleanExpressionPredicate( booleanExpressionPredicate );
}
}
// DB2 does not allow CASE expressions where all result arms contain plain parameters.
// At least one result arm must provide some type context for inference,
// so we cast the first result arm if we encounter this condition
@Override
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression caseSearchedExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
caseSearchedExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer );
}
}
@Override
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression caseSimpleExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) {
final List<CaseSimpleExpression.WhenFragment> whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
caseSimpleExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer );
}
}
@Override
protected String getForUpdate() {
return " for read only with rs use and keep update locks";
@ -146,7 +218,7 @@ public class DB2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAst
for ( int i = 0; i < size; i++ ) {
appendSql( separator );
appendSql( returningColumns.get( i ).getColumnExpression() );
separator = ", ";
separator = ",";
}
if ( statement instanceof DeleteStatement ) {
appendSql( " from old table (" );

View File

@ -79,8 +79,8 @@ public class DB2iDialect extends DB2Dialect {
public String getQuerySequencesString() {
if ( getIVersion() >= 730 ) {
return "select distinct sequence_name from qsys2.syssequences " +
"where ( current_schema = '*LIBL' and sequence_schema in ( select schema_name from qsys2.library_list_info ) ) " +
"or sequence_schema = current_schema";
"where current_schema='*LIBL' and sequence_schema in (select schema_name from qsys2.library_list_info) " +
"or sequence_schema=current_schema";
}
else {
return null;

View File

@ -11,6 +11,7 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.DerbyConcatFunction;
import org.hibernate.dialect.function.DerbyLpadEmulation;
import org.hibernate.dialect.function.DerbyRpadEmulation;
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
@ -183,6 +184,9 @@ public class DerbyDialect extends Dialect {
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
// Derby needs an actual argument type for aggregates like SUM, AVG, MIN, MAX to determine the result type
CommonFunctionFactory.aggregates( queryEngine, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
CommonFunctionFactory.concat_pipeOperator( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.chr_char( queryEngine );
@ -209,6 +213,8 @@ public class DerbyDialect extends Dialect {
.setExactArgumentCount( 2 )
.register();
queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatFunction() );
//no way I can see to pad with anything other than spaces
queryEngine.getSqmFunctionRegistry().register( "lpad", new DerbyLpadEmulation() );
queryEngine.getSqmFunctionRegistry().register( "rpad", new DerbyRpadEmulation() );
@ -252,14 +258,14 @@ public class DerbyDialect extends Dialect {
case DAY_OF_MONTH:
return "day(?2)";
case DAY_OF_YEAR:
return "({fn timestampdiff(sql_tsi_day, date(char(year(?2),4)||'-01-01'),?2)}+1)";
return "({fn timestampdiff(sql_tsi_day,date(char(year(?2),4)||'-01-01'),?2)}+1)";
case DAY_OF_WEEK:
// Use the approach as outlined here: https://stackoverflow.com/questions/36357013/day-of-week-from-seconds-since-epoch
return "(mod(mod({fn timestampdiff(sql_tsi_day, {d '1970-01-01'}, ?2)}+4,7)+7,7)+1)";
return "(mod(mod({fn timestampdiff(sql_tsi_day,{d '1970-01-01'},?2)}+4,7)+7,7)+1)";
case WEEK:
// Use the approach as outlined here: https://www.sqlservercentral.com/articles/a-simple-formula-to-calculate-the-iso-week-number
// In SQL Server terms this is (DATEPART(dy,DATEADD(dd,DATEDIFF(dd,'17530101',@SomeDate)/7*7,'17530104'))+6)/7
return "(({fn timestampdiff(sql_tsi_day, date(char(year(?2),4)||'-01-01'),{fn timestampadd(sql_tsi_day, {fn timestampdiff(sql_tsi_day, {d '1753-01-01'}, ?2)}/7*7, {d '1753-01-04'})})}+7)/7)";
return "(({fn timestampdiff(sql_tsi_day,date(char(year(?2),4)||'-01-01'),{fn timestampadd(sql_tsi_day,{fn timestampdiff(sql_tsi_day,{d '1753-01-01'},?2)}/7*7,{d '1753-01-04'})})}+7)/7)";
case QUARTER:
return "((month(?2)+2)/3)";
default:
@ -320,9 +326,9 @@ public class DerbyDialect extends Dialect {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "{fn timestampadd(sql_tsi_frac_second, mod(bigint(?2),1000000000), {fn timestampadd(sql_tsi_second, bigint((?2)/1000000000), ?3)})}";
return "{fn timestampadd(sql_tsi_frac_second,mod(bigint(?2),1000000000),{fn timestampadd(sql_tsi_second,bigint((?2)/1000000000),?3)})}";
default:
return "{fn timestampadd(sql_tsi_?1, bigint(?2), ?3)}";
return "{fn timestampadd(sql_tsi_?1,bigint(?2),?3)}";
}
}
@ -331,9 +337,9 @@ public class DerbyDialect extends Dialect {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "{fn timestampdiff(sql_tsi_frac_second, ?2, ?3)}";
return "{fn timestampdiff(sql_tsi_frac_second,?2,?3)}";
default:
return "{fn timestampdiff(sql_tsi_?1, ?2, ?3)}";
return "{fn timestampdiff(sql_tsi_?1,?2,?3)}";
}
}
@ -368,7 +374,7 @@ public class DerbyDialect extends Dialect {
public String getQuerySequencesString() {
return getVersion() < 1060
? null
: "select sys.sysschemas.schemaname as sequence_schema, sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid = sys.sysschemas.schemaid";
: "select sys.sysschemas.schemaname as sequence_schema,sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid=sys.sysschemas.schemaid";
}
@Override

View File

@ -7,24 +7,24 @@
package org.hibernate.dialect;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteContainer;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.NullnessLiteral;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -39,6 +39,68 @@ public class DerbySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
booleanExpressionPredicate.getExpression().accept( this );
}
// Derby does not allow CASE expressions where all result arms contain plain parameters.
// At least one result arm must provide some type context for inference,
// so we cast the first result arm if we encounter this condition
@Override
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression caseSearchedExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
caseSearchedExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer );
}
}
@Override
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression caseSimpleExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) {
final List<CaseSimpleExpression.WhenFragment> whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
caseSimpleExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer );
}
}
@Override
protected String getForUpdate() {
return " for update";
@ -139,6 +201,28 @@ public class DerbySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
}
}
@Override
public void visitInListPredicate(InListPredicate inListPredicate) {
final List<Expression> listExpressions = inListPredicate.getListExpressions();
if ( listExpressions.isEmpty() ) {
appendSql( "1=0" );
return;
}
final Expression testExpression = inListPredicate.getTestExpression();
if ( isParameter( testExpression ) ) {
renderCasted( testExpression );
if ( inListPredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( " in(" );
renderCommaSeparated( listExpressions );
appendSql( CLOSE_PARENTHESIS );
}
else {
super.visitInListPredicate( inListPredicate );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
@ -156,7 +240,7 @@ public class DerbySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
@Override
protected String getFromDual() {
return " from (values 0) as dual";
return " from (values 0) dual";
}
@Override

View File

@ -70,6 +70,7 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.*;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
@ -475,7 +476,7 @@ public abstract class Dialect implements ConversionContext {
//aggregate functions, supported on every database
CommonFunctionFactory.aggregates( queryEngine );
CommonFunctionFactory.aggregates( queryEngine, SqlAstNodeRenderingMode.DEFAULT );
//the ANSI SQL-defined aggregate functions any() and every() are only
//supported on one database, but can be emulated using sum() and case,

View File

@ -41,6 +41,7 @@ import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction;
import org.hibernate.query.sqm.mutation.internal.idtable.IdTable;
import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
@ -155,6 +156,9 @@ public class H2Dialect extends Dialect {
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
// H2 needs an actual argument type for aggregates like SUM, AVG, MIN, MAX to determine the result type
CommonFunctionFactory.aggregates( queryEngine, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
CommonFunctionFactory.pi( queryEngine );
CommonFunctionFactory.cot( queryEngine );
CommonFunctionFactory.radians( queryEngine );
@ -246,13 +250,13 @@ public class H2Dialect extends Dialect {
@Override
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
return "dateadd(?1, ?2, ?3)";
return "dateadd(?1,?2,?3)";
}
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
return "datediff(?1, ?2, ?3)";
return "datediff(?1,?2,?3)";
}
@Override

View File

@ -18,6 +18,7 @@ import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -32,6 +33,16 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
booleanExpressionPredicate.getExpression().accept( this );
}
@Override
public void visitOffsetFetchClause(QueryPart queryPart) {
if ( isRowsOnlyFetchClauseType( queryPart ) ) {

View File

@ -284,13 +284,13 @@ public class HSQLDialect extends Dialect {
switch (unit) {
case NANOSECOND:
case NATIVE:
pattern.append("timestampadd(sql_tsi_frac_second, ?2, "); //nanos
pattern.append("timestampadd(sql_tsi_frac_second,?2,"); //nanos
break;
case WEEK:
pattern.append("dateadd('day', ?2*7, ");
pattern.append("dateadd('day',?2*7,");
break;
default:
pattern.append("dateadd('?1', ?2, ");
pattern.append("dateadd('?1',?2,");
}
if (castTo) {
pattern.append("cast(?3 as timestamp)");
@ -317,14 +317,14 @@ public class HSQLDialect extends Dialect {
default:
pattern.append("datediff('?1'");
}
pattern.append(", ");
pattern.append(',');
if (castFrom) {
pattern.append("cast(?2 as timestamp)");
}
else {
pattern.append("?2");
}
pattern.append(", ");
pattern.append(',');
if (castTo) {
pattern.append("cast(?3 as timestamp)");
}

View File

@ -7,6 +7,7 @@
package org.hibernate.dialect;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
@ -15,10 +16,13 @@ import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.exec.spi.JdbcOperation;
@ -34,6 +38,68 @@ public class HSQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAs
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
booleanExpressionPredicate.getExpression().accept( this );
}
// HSQL does not allow CASE expressions where all result arms contain plain parameters.
// At least one result arm must provide some type context for inference,
// so we cast the first result arm if we encounter this condition
@Override
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression caseSearchedExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
caseSearchedExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer );
}
}
@Override
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression caseSimpleExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) {
final List<CaseSimpleExpression.WhenFragment> whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
caseSimpleExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer );
}
}
@Override
public boolean supportsFilterClause() {
return true;
@ -98,9 +164,7 @@ public class HSQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAs
case NOT_DISTINCT_FROM:
// HSQL does not like parameters in the distinct from predicate
render( lhs, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
appendSql( " " );
appendSql( operator.sqlText() );
appendSql( " " );
render( rhs, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
break;
default:

View File

@ -131,7 +131,7 @@ public class MariaDBDialect extends MySQLDialect {
@Override
public String getQuerySequencesString() {
return getSequenceSupport().supportsSequences()
? "select table_name from information_schema.TABLES where table_schema = database() and table_type = 'SEQUENCE'"
? "select table_name from information_schema.TABLES where table_schema=database() and table_type='SEQUENCE'"
: super.getQuerySequencesString(); //fancy way to write "null"
}

View File

@ -14,6 +14,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -30,6 +31,16 @@ public class MariaDBSqlAstTranslator<T extends JdbcOperation> extends AbstractSq
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
booleanExpressionPredicate.getExpression().accept( this );
}
@Override
protected String getForShare() {
return " lock in share mode";

View File

@ -465,11 +465,11 @@ public class MySQLDialect extends Dialect {
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
switch (unit) {
case NANOSECOND:
return "timestampadd(microsecond, (?2)/1e3, ?3)";
return "timestampadd(microsecond,(?2)/1e3,?3)";
case NATIVE:
return "timestampadd(microsecond, ?2, ?3)";
return "timestampadd(microsecond,?2,?3)";
default:
return "timestampadd(?1, ?2, ?3)";
return "timestampadd(?1,?2,?3)";
}
}
@ -477,11 +477,11 @@ public class MySQLDialect extends Dialect {
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
switch (unit) {
case NANOSECOND:
return "timestampdiff(microsecond, ?2, ?3)*1e3";
return "timestampdiff(microsecond,?2,?3)*1e3";
case NATIVE:
return "timestampdiff(microsecond, ?2, ?3)";
return "timestampdiff(microsecond,?2,?3)";
default:
return "timestampdiff(?1, ?2, ?3)";
return "timestampdiff(?1,?2,?3)";
}
}
@ -773,7 +773,7 @@ public class MySQLDialect extends Dialect {
else {
orderByElement.append( "1 else 0" );
}
orderByElement.append( " end, " );
orderByElement.append( " end," );
}
// Nulls precedence has already been handled so passing NONE value.
orderByElement.append( super.renderOrderByElement( expression, collation, order, NullPrecedence.NONE ) );

View File

@ -14,6 +14,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -30,6 +31,16 @@ public class MySQLSqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
booleanExpressionPredicate.getExpression().accept( this );
}
@Override
protected String getForShare() {
return getDialect().getVersion() >= 800 ? " for share" : " lock in share mode";

View File

@ -172,6 +172,7 @@ public class OracleDialect extends Dialect {
CommonFunctionFactory.covarPopSamp( queryEngine );
CommonFunctionFactory.corr( queryEngine );
CommonFunctionFactory.regrLinearRegressionAggregates( queryEngine );
CommonFunctionFactory.bitLength_pattern( queryEngine, "vsize(?1)*8" );
if ( getVersion() < 900 ) {
queryEngine.getSqmFunctionRegistry().register( "coalesce", new NvlCoalesceEmulation() );
@ -184,8 +185,8 @@ public class OracleDialect extends Dialect {
queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern(
"locate",
StandardBasicTypes.INTEGER,
"instr(?2, ?1)",
"instr(?2, ?1, ?3)"
"instr(?2,?1)",
"instr(?2,?1,?3)"
).setArgumentListSignature("(pattern, string[, start])");
}
@ -367,7 +368,7 @@ public class OracleDialect extends Dialect {
@Override
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
StringBuilder pattern = new StringBuilder();
pattern.append("(?3 + ");
pattern.append("(?3+");
switch ( unit ) {
case YEAR:
case QUARTER:
@ -1005,7 +1006,7 @@ public class OracleDialect extends Dialect {
@Override
public String getCurrentSchemaCommand() {
return "SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL";
return "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL";
}
@Override

View File

@ -163,7 +163,7 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
appendSql( ')' );
}
}
appendSql( " where rownum <= " );
appendSql( " where rownum<=" );
final Stack<Clause> clauseStack = getClauseStack();
clauseStack.push( Clause.WHERE );
try {
@ -307,7 +307,7 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
visitDecodeCaseSearchedExpression( caseSearchedExpression );
}
else {
visitAnsiCaseSearchedExpression( caseSearchedExpression );
super.visitCaseSearchedExpression( caseSearchedExpression, inSelect );
}
}

View File

@ -175,15 +175,15 @@ public class PostgreSQLDialect extends Dialect {
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
switch ( unit ) {
case NANOSECOND:
return "(?3 + (?2)/1e3 * interval '1 microsecond')";
return "(?3+(?2)/1e3*interval '1 microsecond')";
case NATIVE:
return "(?3 + (?2) * interval '1 second')";
return "(?3+(?2)*interval '1 second')";
case QUARTER: //quarter is not supported in interval literals
return "(?3 + (?2) * interval '3 month')";
return "(?3+(?2)*interval '3 month')";
case WEEK: //week is not supported in interval literals
return "(?3 + (?2) * interval '7 day')";
return "(?3+(?2)*interval '7 day')";
default:
return "(?3 + (?2) * interval '1 ?1')";
return "(?3+(?2)*interval '1 ?1')";
}
}
@ -324,7 +324,7 @@ public class PostgreSQLDialect extends Dialect {
"locate",
StandardBasicTypes.INTEGER,
"position(?1 in ?2)",
"(position(?1 in substring(?2 from ?3)) + (?3) - 1)"
"(position(?1 in substring(?2 from ?3))+(?3)-1)"
).setArgumentListSignature("(pattern, string[, start])");
if ( getVersion() >= 940 ) {

View File

@ -15,6 +15,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.select.QueryGroup;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -31,6 +32,16 @@ public class PostgreSQLSqlAstTranslator<T extends JdbcOperation> extends Abstrac
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
booleanExpressionPredicate.getExpression().accept( this );
}
@Override
protected void renderMaterializationHint(CteMaterialization materialization) {
if ( getDialect().getVersion() >= 1200 ) {

View File

@ -148,6 +148,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
CommonFunctionFactory.truncate_round( queryEngine );
CommonFunctionFactory.everyAny_sumIif( queryEngine );
CommonFunctionFactory.bitLength_pattern( queryEngine, "datalength(?1) * 8" );
if ( getVersion() >= 10 ) {
CommonFunctionFactory.locate_charindex( queryEngine );
@ -237,7 +238,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
@Override
public String currentTime() {
return "convert(time, getdate())";
return "convert(time,getdate())";
}
@Override
@ -298,24 +299,24 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
lockMode = lockOptions.getLockMode();
}
final String writeLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "updlock, holdlock";
final String writeLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "updlock,holdlock";
final String readLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock";
final String noWaitStr = lockOptions.getTimeOut() == LockOptions.NO_WAIT ? ", nowait" : "";
final String skipLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? ", readpast" : "";
final String noWaitStr = lockOptions.getTimeOut() == LockOptions.NO_WAIT ? ",nowait" : "";
final String skipLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? ",readpast" : "";
switch ( lockMode ) {
//noinspection deprecation
case UPGRADE:
case PESSIMISTIC_WRITE:
case WRITE:
return tableName + " with (" + writeLockStr + ", rowlock" + noWaitStr + skipLockStr + ")";
return tableName + " with (" + writeLockStr + ",rowlock" + noWaitStr + skipLockStr + ")";
case PESSIMISTIC_READ:
return tableName + " with (" + readLockStr + ", rowlock" + noWaitStr + skipLockStr + ")";
return tableName + " with (" + readLockStr + ",rowlock" + noWaitStr + skipLockStr + ")";
case UPGRADE_SKIPLOCKED:
return tableName + " with (updlock, rowlock, readpast" + noWaitStr + ")";
return tableName + " with (updlock,rowlock,readpast" + noWaitStr + ")";
case UPGRADE_NOWAIT:
return tableName + " with (updlock, holdlock, rowlock, nowait)";
return tableName + " with (updlock,holdlock,rowlock,nowait)";
default:
return tableName;
}
@ -327,11 +328,11 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
case UPGRADE_NOWAIT:
case PESSIMISTIC_WRITE:
case WRITE:
return tableName + " with (updlock, rowlock)";
return tableName + " with (updlock,rowlock)";
case PESSIMISTIC_READ:
return tableName + " with (holdlock, rowlock)";
return tableName + " with (holdlock,rowlock)";
case UPGRADE_SKIPLOCKED:
return tableName + " with (updlock, rowlock, readpast)";
return tableName + " with (updlock,rowlock,readpast)";
default:
return tableName;
}
@ -501,7 +502,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
else {
orderByElement.append( "1 else 0" );
}
orderByElement.append( " end, " );
orderByElement.append( " end," );
}
// Nulls precedence has already been handled so passing NONE value.
@ -593,12 +594,12 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
//Java Durations are usually the only thing
//we find expressed in nanosecond precision,
//and they can easily be very large
return "dateadd(nanosecond, ?2%1000000000, dateadd(second, ?2/1000000000, ?3))";
return "dateadd(nanosecond,?2%1000000000,dateadd(second,?2/1000000000,?3))";
case NATIVE:
//microsecond is the "native" precision
return "dateadd(microsecond, ?2%1000000, dateadd(second, ?2/1000000, ?3))";
return "dateadd(microsecond,?2%1000000,dateadd(second,?2/1000000,?3))";
default:
return "dateadd(?1, ?2, ?3)";
return "dateadd(?1,?2,?3)";
}
}
@ -607,14 +608,14 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
switch (unit) {
case NATIVE:
//use microsecond as the "native" precision
return "datediff_big(microsecond, ?2, ?3)";
return "datediff_big(microsecond,?2,?3)";
default:
//datediff() returns an int, and can easily
//overflow when dealing with "physical"
//durations, so use datediff_big()
return unit.normalized() == NANOSECOND
? "datediff_big(?1, ?2, ?3)"
: "datediff(?1, ?2, ?3)";
? "datediff_big(?1,?2,?3)"
: "datediff(?1,?2,?3)";
}
}

View File

@ -66,7 +66,7 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
if ( rendersTableReferenceAlias( currentClause ) ) {
final String identificationVariable = tableReference.getIdentificationVariable();
if ( identificationVariable != null ) {
appendSql( getDialect().getTableAliasSeparator() );
appendSql( ' ' );
appendSql( identificationVariable );
}
}
@ -82,27 +82,27 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
private void renderLockHint(LockMode lockMode) {
if ( getDialect().getVersion() >= 9 ) {
final int effectiveLockTimeout = getEffectiveLockTimeout( lockMode );
final String writeLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "updlock, holdlock";
final String writeLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "updlock,holdlock";
final String readLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock";
final String noWaitStr = effectiveLockTimeout == LockOptions.NO_WAIT ? ", nowait" : "";
final String skipLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? ", readpast" : "";
final String noWaitStr = effectiveLockTimeout == LockOptions.NO_WAIT ? ",nowait" : "";
final String skipLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? ",readpast" : "";
switch ( lockMode ) {
//noinspection deprecation
case UPGRADE:
case PESSIMISTIC_WRITE:
case WRITE:
appendSql( " with (" + writeLockStr + ", rowlock" + noWaitStr + skipLockStr + ")" );
appendSql( " with (" + writeLockStr + ",rowlock" + noWaitStr + skipLockStr + ")" );
break;
case PESSIMISTIC_READ:
appendSql( " with (" + readLockStr + ", rowlock" + noWaitStr + skipLockStr + ")" );
appendSql( " with (" + readLockStr + ",rowlock" + noWaitStr + skipLockStr + ")" );
break;
case UPGRADE_SKIPLOCKED:
appendSql( " with (updlock, rowlock, readpast" + noWaitStr + ")" );
appendSql( " with (updlock,rowlock,readpast" + noWaitStr + ")" );
break;
case UPGRADE_NOWAIT:
appendSql( " with (updlock, holdlock, rowlock, nowait)" );
appendSql( " with (updlock,holdlock,rowlock,nowait)" );
break;
}
}
@ -113,13 +113,13 @@ public class SQLServerSqlAstTranslator<T extends JdbcOperation> extends Abstract
case UPGRADE_NOWAIT:
case PESSIMISTIC_WRITE:
case WRITE:
appendSql( " with (updlock, rowlock)" );
appendSql( " with (updlock,rowlock)" );
break;
case PESSIMISTIC_READ:
appendSql(" with (holdlock, rowlock)" );
appendSql(" with (holdlock,rowlock)" );
break;
case UPGRADE_SKIPLOCKED:
appendSql( " with (updlock, rowlock, readpast)" );
appendSql( " with (updlock,rowlock,readpast)" );
break;
}
}

View File

@ -445,7 +445,7 @@ public class SpannerDialect extends Dialect {
case MONTH:
throw new SemanticException("illegal unit for timestamp_add(): " + unit);
default:
return "timestamp_add(?3, interval ?2 ?1)";
return "timestamp_add(?3,interval ?2 ?1)";
}
}
else {
@ -457,7 +457,7 @@ public class SpannerDialect extends Dialect {
case NATIVE:
throw new SemanticException("illegal unit for date_add(): " + unit);
default:
return "date_add(?3, interval ?2 ?1)";
return "date_add(?3,interval ?2 ?1)";
}
}
}
@ -471,7 +471,7 @@ public class SpannerDialect extends Dialect {
case MONTH:
throw new SemanticException("illegal unit for timestamp_diff(): " + unit);
default:
return "timestamp_diff(?3, ?2, ?1)";
return "timestamp_diff(?3,?2,?1)";
}
}
else {
@ -483,7 +483,7 @@ public class SpannerDialect extends Dialect {
case NATIVE:
throw new SemanticException("illegal unit for date_diff(): " + unit);
default:
return "date_diff(?3, ?2, ?1)";
return "date_diff(?3,?2,?1)";
}
}
}

View File

@ -219,13 +219,13 @@ public class SybaseASEDialect extends SybaseDialect {
// If the driver or database do not support bigdatetime and bigtime types,
// we try to operate on milliseconds instead
if ( getVersion() < 1550 || jtdsDriver ) {
return "dateadd(millisecond, ?2/1000000, ?3)";
return "dateadd(millisecond,?2/1000000,?3)";
}
else {
return "dateadd(mcs, ?2/1000, ?3)";
return "dateadd(mcs,?2/1000,?3)";
}
default:
return "dateadd(?1, ?2, ?3)";
return "dateadd(?1,?2,?3)";
}
}
@ -235,9 +235,9 @@ public class SybaseASEDialect extends SybaseDialect {
switch ( unit ) {
case NANOSECOND:
case NATIVE:
return "(datediff(mcs, ?2, ?3)*1000)";
return "(datediff(mcs,?2,?3)*1000)";
default:
return "datediff(?1, ?2, ?3)";
return "datediff(?1,?2,?3)";
}
}

View File

@ -7,16 +7,20 @@
package org.hibernate.dialect;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.MutationStatement;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
@ -44,6 +48,58 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
super( sessionFactory, statement );
}
// Sybase ASE does not allow CASE expressions where all result arms contain plain parameters.
// At least one result arm must provide some type context for inference,
// so we cast the first result arm if we encounter this condition
@Override
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression caseSearchedExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
caseSearchedExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer );
}
}
@Override
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression caseSimpleExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) {
final List<CaseSimpleExpression.WhenFragment> whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
caseSimpleExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer );
}
}
@Override
protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) {
super.renderTableReference( tableReference, lockMode );
@ -168,14 +224,13 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
boolean rhsNotNullPredicate =
lhs instanceof NullnessLiteral
|| lhs instanceof Literal
|| lhs instanceof JdbcParameter;
|| isParameter( lhs );
boolean lhsNotNullPredicate =
rhs instanceof NullnessLiteral
|| rhs instanceof Literal
|| rhs instanceof JdbcParameter;
|| isParameter( rhs );
if ( rhsNotNullPredicate || lhsNotNullPredicate ) {
lhs.accept( this );
appendSql( " " );
switch ( operator ) {
case DISTINCT_FROM:
appendSql( "<>" );
@ -194,7 +249,6 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
appendSql( operator.sqlText() );
break;
}
appendSql( " " );
rhs.accept( this );
if ( lhsNotNullPredicate ) {
appendSql( " and " );
@ -308,7 +362,7 @@ public class SybaseASESqlAstTranslator<T extends JdbcOperation> extends Abstract
@Override
protected String getFromDual() {
return " from (select 1) as dual(c1)";
return " from (select 1) dual(c1)";
}
private boolean supportsTopClause() {

View File

@ -215,6 +215,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
CommonFunctionFactory.replace_strReplace( queryEngine );
CommonFunctionFactory.everyAny_sumCaseCase( queryEngine );
CommonFunctionFactory.bitLength_pattern( queryEngine, "datalength(?1) * 8" );
}
@Override
@ -238,11 +239,11 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
if ( to == CastType.STRING ) {
switch ( from ) {
case DATE:
return "str_replace(convert(varchar, ?1, 102), '.', '-')";
return "str_replace(convert(varchar,?1,102),'.','-')";
case TIME:
return "convert(varchar, ?1, 108)";
return "convert(varchar,?1,108)";
case TIMESTAMP:
return "str_replace(convert(varchar, ?1, 23), 'T', ' ')";
return "str_replace(convert(varchar,?1,23),'T',' ')";
}
}
return super.castPattern( from, to );
@ -259,7 +260,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
@Override
public String extractPattern(TemporalUnit unit) {
//TODO!!
return "datepart(?1, ?2)";
return "datepart(?1,?2)";
}
@Override
@ -270,13 +271,13 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
@Override
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) {
//TODO!!
return "dateadd(?1, ?2, ?3)";
return "dateadd(?1,?2,?3)";
}
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
//TODO!!
return "datediff(?1, ?2, ?3)";
return "datediff(?1,?2,?3)";
}
@Override

View File

@ -7,14 +7,18 @@
package org.hibernate.dialect;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
@ -35,6 +39,58 @@ public class SybaseSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
super( sessionFactory, statement );
}
// Sybase does not allow CASE expressions where all result arms contain plain parameters.
// At least one result arm must provide some type context for inference,
// so we cast the first result arm if we encounter this condition
@Override
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression caseSearchedExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
caseSearchedExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer );
}
}
@Override
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression caseSimpleExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) {
final List<CaseSimpleExpression.WhenFragment> whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
caseSimpleExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer );
}
}
@Override
protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) {
super.renderTableReference( tableReference, lockMode );

View File

@ -0,0 +1,39 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.dialect.function;
import java.util.List;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.StandardBasicTypes;
public class DerbyConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
public DerbyConcatFunction() {
super(
"concat",
StandardArgumentsValidators.min( 1 ),
StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING )
);
}
@Override
public void render(SqlAppender sqlAppender, List<SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
sqlAppender.appendSql( '(' );
walker.render( sqlAstArguments.get( 0 ), SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
for ( int i = 1; i < sqlAstArguments.size(); i++ ) {
sqlAppender.appendSql( "||" );
walker.render( sqlAstArguments.get( i ), SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
}
sqlAppender.appendSql( ')' );
}
}

View File

@ -34,7 +34,7 @@ public class FieldFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
sqlAppender.appendSql( "field(" );
sqlAstArguments.get( 0 ).accept( walker );
for ( int i = 1; i < sqlAstArguments.size(); i++ ) {
sqlAppender.appendSql( ", " );
sqlAppender.appendSql( ',' );
final SqlAstNode argument = sqlAstArguments.get( i );
final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple( argument );
@ -42,7 +42,7 @@ public class FieldFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
final List<? extends Expression> expressions = sqlTuple.getExpressions();
for ( int j = 0; j < expressions.size(); j++ ) {
if ( j != 0 ) {
sqlAppender.appendSql( ", " );
sqlAppender.appendSql( ',' );
}
expressions.get( j ).accept( walker );
}

View File

@ -46,12 +46,12 @@ public class QuantifiedLeastGreatestEmulation
sqlAppender.appendSql( " when " );
arguments.get( i ).accept( walker );
sqlAppender.appendSql( operator );
sqlAppender.appendSql( " all(" );
sqlAppender.appendSql( "all(" );
String separator = "";
for ( int j = i + 1; j < numberOfArguments; j++ ) {
sqlAppender.appendSql( separator );
arguments.get( j ).accept( walker );
separator = ", ";
separator = ",";
}
sqlAppender.appendSql( ") then " );
arguments.get( i ).accept( walker );

View File

@ -63,7 +63,7 @@ public class TransactSQLStrFunction extends CastStrEmulation implements Function
sqlAppender.appendSql( "str(" );
arguments.get( 0 ).accept( walker );
for ( int i = 1; i < arguments.size(); i++ ) {
sqlAppender.appendSql( ", " );
sqlAppender.appendSql( ',' );
arguments.get( i ).accept( walker );
}
sqlAppender.appendSql( ')' );

View File

@ -22,9 +22,9 @@ public class LegacyDB2LimitHandler extends AbstractLimitHandler {
public String processSql(String sql, RowSelection selection) {
if ( hasFirstRow( selection ) ) {
//nest the main query in an outer select
return "select * from ( select row_.*, rownumber() over(order by order of row_) as rownumber_ from ( "
return "select * from (select row_.*,rownumber() over(order by order of row_) as rownumber_ from ("
+ sql + fetchFirstRows( selection )
+ " ) as row_ ) as query_ where rownumber_ > "
+ ") as row_) as query_ where rownumber_>"
+ selection.getFirstRow()
+ " order by rownumber_";
}
@ -43,9 +43,9 @@ public class LegacyDB2LimitHandler extends AbstractLimitHandler {
public String processSql(String sql, Limit limit) {
if ( hasFirstRow( limit ) ) {
//nest the main query in an outer select
return "select * from ( select row_.*, rownumber() over(order by order of row_) as rownumber_ from ( "
return "select * from (select row_.*,rownumber() over(order by order of row_) as rownumber_ from ("
+ sql + fetchFirstRows( limit )
+ " ) as row_ ) as query_ where rownumber_ > "
+ ") as row_) as query_ where rownumber_>"
+ limit.getFirstRow()
+ " order by rownumber_";
}

View File

@ -38,16 +38,16 @@ public class LegacyOracleLimitHandler extends AbstractLimitHandler {
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 );
if ( hasOffset ) {
pagingSelect.append( "select * from (select row_.*, rownum rownum_ from (" ).append( sql );
pagingSelect.append( "select * from (select row_.*,rownum rownum_ from (" ).append( sql );
if ( version < 900 ) {
pagingSelect.append( ") row_) where rownum_ <= ? and rownum_ > ?" );
pagingSelect.append( ") row_) where rownum_<=? and rownum_>?" );
}
else {
pagingSelect.append( ") row_ where rownum <= ?) where rownum_ > ?" );
pagingSelect.append( ") row_ where rownum<=?) where rownum_>?" );
}
}
else {
pagingSelect.append( "select * from (" ).append( sql ).append( ") where rownum <= ?" );
pagingSelect.append( "select * from (" ).append( sql ).append( ") where rownum<=?" );
}
if ( forUpdateClause != null ) {
@ -73,16 +73,16 @@ public class LegacyOracleLimitHandler extends AbstractLimitHandler {
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 );
if ( hasOffset ) {
pagingSelect.append( "select * from (select row_.*, rownum rownum_ from (" ).append( sql );
pagingSelect.append( "select * from (select row_.*,rownum rownum_ from (" ).append( sql );
if ( version < 900 ) {
pagingSelect.append( ") row_) where rownum_ <= ? and rownum_ > ?" );
pagingSelect.append( ") row_) where rownum_<=? and rownum_>?" );
}
else {
pagingSelect.append( ") row_ where rownum <= ?) where rownum_ > ?" );
pagingSelect.append( ") row_ where rownum<=?) where rownum_>?" );
}
}
else {
pagingSelect.append( "select * from (" ).append( sql ).append( ") where rownum <= ?" );
pagingSelect.append( "select * from (" ).append( sql ).append( ") where rownum<=?" );
}
if ( forUpdateClause != null ) {

View File

@ -25,7 +25,7 @@ public class LimitLimitHandler extends AbstractSimpleLimitHandler {
@Override
protected String limitClause(boolean hasFirstRow) {
return hasFirstRow ? " limit ?, ?" : " limit ?";
return hasFirstRow ? " limit ?,?" : " limit ?";
}
private static final Pattern FOR_UPDATE_PATTERN =

View File

@ -146,15 +146,15 @@ public class Oracle12LimitHandler extends AbstractLimitHandler {
if ( hasFirstRow ) {
pagingSelect = new StringBuilder( sql.length() + forUpdateClauseLength + 98 );
pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " );
pagingSelect.append( "select * from (select row_.*,rownum rownum_ from (" );
pagingSelect.append( sql );
pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" );
pagingSelect.append( ") row_ where rownum<=?) where rownum_>?" );
}
else {
pagingSelect = new StringBuilder( sql.length() + forUpdateClauseLength + 37 );
pagingSelect.append( "select * from ( " );
pagingSelect.append( "select * from (" );
pagingSelect.append( sql );
pagingSelect.append( " ) where rownum <= ?" );
pagingSelect.append( ") where rownum<=?" );
}
if ( isForUpdate ) {

View File

@ -108,9 +108,9 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
String aliases = selectAliases( sql, afterSelectOffset, fromOffset, result ); //warning: changes result by side-effect
result.insert( selectOffset, ( hasCommonTables ? "," : "with" )
+ " query_ as (select row_.*, row_number() over (order by current_timestamp) as rownumber_ from (" )
+ " query_ as (select row_.*,row_number() over (order by current_timestamp) as rownumber_ from (" )
.append( ") row_) select " ).append( aliases )
.append( " from query_ where rownumber_ >= ? and rownumber_ < ?" );
.append( " from query_ where rownumber_>=? and rownumber_<?" );
}
return result.toString();
@ -186,9 +186,9 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
String aliases = selectAliases( sql, afterSelectOffset, fromOffset, result ); //warning: changes result by side-effect
result.insert( selectOffset, ( hasCommonTables ? "," : "with" )
+ " query_ as (select row_.*, row_number() over (order by current_timestamp) as rownumber_ from (" )
+ " query_ as (select row_.*,row_number() over (order by current_timestamp) as rownumber_ from (" )
.append( ") row_) select " ).append( aliases )
.append( " from query_ where rownumber_ >= ? and rownumber_ < ?" );
.append( " from query_ where rownumber_>=? and rownumber_<?" );
}
return result.toString();
@ -272,7 +272,7 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler {
}
while ( offset < fromOffset );
return String.join( ", ", aliases );
return String.join( ",", aliases );
}
private int getAliasIndex(String sql) {

View File

@ -19,6 +19,6 @@ public final class DerbySequenceSupport extends DB2SequenceSupport {
@Override
public String getSelectSequencePreviousValString(String sequenceName) throws MappingException {
return "SYSCS_UTIL.SYSCS_PEEK_AT_SEQUENCE('HIBERNATE_ORM_TEST', '" + sequenceName.toUpperCase() + "')";
return "SYSCS_UTIL.SYSCS_PEEK_AT_SEQUENCE('HIBERNATE_ORM_TEST','" + sequenceName.toUpperCase() + "')";
}
}

View File

@ -19,6 +19,6 @@ public final class SQLServerSequenceSupport extends ANSISequenceSupport {
@Override
public String getSequencePreviousValString(String sequenceName) throws MappingException {
return "select convert(varchar(200), current_value) from sys.sequences where name = '" + sequenceName + "'";
return "select convert(varchar(200),current_value) from sys.sequences where name='" + sequenceName + "'";
}
}

View File

@ -27,6 +27,19 @@ public interface CollectionPart extends ModelPart, Fetchable {
return name;
}
public static Nature fromNameExact(String name) {
switch ( name ) {
case "{element}":
return ELEMENT;
case "{index}":
return INDEX;
case "{collection-id}":
return ID;
}
return null;
}
public static Nature fromName(String name) {
// NOTE : the `$x$` form comes form order-by handling
// todo (6.0) : ^^ convert these to use the `{x}` form instead?

View File

@ -52,10 +52,28 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
ModelPart getTargetPart();
default ModelPart getPart(Nature nature) {
if ( nature == Nature.KEY ) {
return getKeyPart();
}
else {
return getTargetPart();
}
}
Side getKeySide();
Side getTargetSide();
default Side getSide(Nature nature) {
if ( nature == Nature.KEY ) {
return getKeySide();
}
else {
return getTargetSide();
}
}
/**
* Create a DomainResult for the referring-side of the fk
*/

View File

@ -241,7 +241,7 @@ public class ToOneAttributeMapping
}
this.navigableRole = navigableRole;
final CollectionPart.Nature nature = CollectionPart.Nature.fromName(
final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact(
getNavigableRole().getParent().getLocalName()
);
if ( nature == null ) {

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.metamodel.model.domain;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
@ -649,6 +650,28 @@ public abstract class AbstractManagedType<J>
return DomainModelHelper.resolveSubType( this, subType, jpaMetamodel() );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Serialization
protected Object writeReplace() throws ObjectStreamException {
return new SerialForm( jpaMetamodel(), getJavaType() );
}
private static class SerialForm implements Serializable {
private final JpaMetamodel jpaMetamodel;
private final Class<?> typeClass;
public SerialForm(JpaMetamodel jpaMetamodel, Class<?> typeClass) {
this.jpaMetamodel = jpaMetamodel;
this.typeClass = typeClass;
}
private Object readResolve() {
return jpaMetamodel.managedType( typeClass );
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Creation

View File

@ -17,7 +17,7 @@ import org.hibernate.query.sqm.SqmPathSource;
* @author Steve Ebersole
*/
public interface MapPersistentAttribute<D,K,V> extends MapAttribute<D, K, V>, PluralPersistentAttribute<D,Map<K,V>,V> {
SqmPathSource getKeyPathSource();
SqmPathSource<K> getKeyPathSource();
@Override
SimpleDomainType<K> getKeyType();

View File

@ -9,11 +9,13 @@ package org.hibernate.metamodel.model.domain.internal;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import javax.persistence.metamodel.Attribute;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.metamodel.AttributeClassification;
import org.hibernate.metamodel.internal.MetadataContext;
@ -106,49 +108,25 @@ public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,
return declaringType.getTypeName() + '#' + name + '(' + attributeClassification + ')';
}
/**
* Used by JDK serialization...
*
* @param ois The input stream from which we are being read...
* @throws java.io.IOException Indicates a general IO stream exception
* @throws ClassNotFoundException Indicates a class resolution issue
*/
@SuppressWarnings("unchecked")
protected void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
final String memberDeclaringClassName = ( String ) ois.readObject();
final String memberName = ( String ) ois.readObject();
final String memberType = ( String ) ois.readObject();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Serialization
final Class memberDeclaringClass = Class.forName(
memberDeclaringClassName,
false,
declaringType.getJavaType().getClassLoader()
);
try {
this.member = "method".equals( memberType )
? memberDeclaringClass.getMethod( memberName, ReflectHelper.NO_PARAM_SIGNATURE )
: memberDeclaringClass.getField( memberName );
}
catch ( Exception e ) {
throw new IllegalStateException(
"Unable to locate member [" + memberDeclaringClassName + "#"
+ memberName + "]"
);
}
protected Object writeReplace() throws ObjectStreamException {
return new SerialForm( declaringType, name );
}
/**
* Used by JDK serialization...
*
* @param oos The output stream to which we are being written...
* @throws IOException Indicates a general IO stream exception
*/
protected void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject( getJavaMember().getDeclaringClass().getName() );
oos.writeObject( getJavaMember().getName() );
// should only ever be a field or the getter-method...
oos.writeObject( Method.class.isInstance( getJavaMember() ) ? "method" : "field" );
private static class SerialForm implements Serializable {
private final ManagedDomainType<?> declaringType;
private final String name;
public SerialForm(ManagedDomainType<?> declaringType, String name) {
this.declaringType = declaringType;
this.name = name;
}
private Object readResolve() {
return declaringType.findAttribute( name );
}
}
}

View File

@ -76,6 +76,9 @@ public abstract class AbstractPluralAttribute<D, C, E>
@Override
public SqmPathSource<?> findSubPathSource(String name) {
if ( CollectionPart.Nature.ELEMENT.getName().equals( name ) ) {
return elementPathSource;
}
return elementPathSource.findSubPathSource( name );
}

View File

@ -10,7 +10,6 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.IllegalPathUsageException;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
@ -37,7 +36,7 @@ public class BasicSqmPathSource<J>
@Override
public SqmPathSource<?> findSubPathSource(String name) {
throw new IllegalPathUsageException( "Basic paths cannot be dereferenced" );
throw new IllegalStateException( "Basic paths cannot be dereferenced" );
}
@Override

View File

@ -9,11 +9,12 @@ package org.hibernate.metamodel.model.domain.internal;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.PathException;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.IllegalPathUsageException;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
@ -65,7 +66,14 @@ public class DiscriminatorSqmPath extends AbstractSqmPath implements SelfInterpr
assert entityDescriptor.hasSubclasses();
final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( getLhs().getNavigablePath() );
final EntityMappingType entityMapping = ( (EntityValuedModelPart) tableGroup.getModelPart() ).getEntityMappingType();
final ModelPartContainer modelPart = tableGroup.getModelPart();
final EntityMappingType entityMapping;
if ( modelPart instanceof EntityValuedModelPart ) {
entityMapping = ( (EntityValuedModelPart) modelPart ).getEntityMappingType();
}
else {
entityMapping = (EntityMappingType) ( (PluralAttributeMapping) modelPart ).getElementDescriptor().getPartMappingType();
}
return new DiscriminatorPathInterpretation( getNavigablePath(), entityMapping, tableGroup, sqlAstCreationState );
}
@ -79,7 +87,7 @@ public class DiscriminatorSqmPath extends AbstractSqmPath implements SelfInterpr
@Override
public SemanticPathPart resolvePathPart(String name, boolean isTerminal, SqmCreationState creationState) {
throw new IllegalPathUsageException( "Discriminator cannot be de-referenced" );
throw new IllegalStateException( "Discriminator cannot be de-referenced" );
}
@Override

View File

@ -10,7 +10,6 @@ import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.sqm.IllegalPathUsageException;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmPath;
@ -38,7 +37,7 @@ public class DiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D> {
}
@Override
public SqmPathSource<?> findSubPathSource(String name) throws IllegalPathUsageException {
throw new IllegalPathUsageException( "Entity discriminator cannot be de-referenced" );
public SqmPathSource<?> findSubPathSource(String name) {
throw new IllegalStateException( "Entity discriminator cannot be de-referenced" );
}
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.metamodel.model.domain.internal;
import java.io.ObjectStreamException;
import java.io.Serializable;
import javax.persistence.metamodel.EntityType;
@ -13,6 +14,7 @@ import org.hibernate.graph.internal.SubGraphImpl;
import org.hibernate.graph.spi.SubGraphImplementor;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.model.domain.AbstractIdentifiableType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
@ -123,7 +125,7 @@ public class EntityTypeImpl<J>
return attribute;
}
if ( "id".equalsIgnoreCase( name ) ) {
if ( "id".equalsIgnoreCase( name ) || EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name ) ) {
//noinspection unchecked
final SingularPersistentAttribute<J, ?> idAttribute = findIdAttribute();
//noinspection RedundantIfStatement
@ -188,4 +190,26 @@ public class EntityTypeImpl<J>
"EntityType cannot be used to create an SqmPath - that would be an SqmFrom which are created directly"
);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Serialization
protected Object writeReplace() throws ObjectStreamException {
return new SerialForm( jpaMetamodel(), getHibernateEntityName() );
}
private static class SerialForm implements Serializable {
private final JpaMetamodel jpaMetamodel;
private final String hibernateEntityName;
public SerialForm(JpaMetamodel jpaMetamodel, String hibernateEntityName) {
this.jpaMetamodel = jpaMetamodel;
this.hibernateEntityName = hibernateEntityName;
}
private Object readResolve() {
return jpaMetamodel.entity( hibernateEntityName );
}
}
}

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.metamodel.model.domain.internal;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@ -24,10 +26,12 @@ import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.internal.RootGraphImpl;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphImplementor;
@ -58,7 +62,7 @@ import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Steve Ebersole
*/
public class JpaMetamodelImpl implements JpaMetamodel {
public class JpaMetamodelImpl implements JpaMetamodel, Serializable {
private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( JpaMetamodel.class );
private static final ImportInfo<?> INVALID_IMPORT = new ImportInfo<>( null, null );
@ -655,4 +659,24 @@ public class JpaMetamodelImpl implements JpaMetamodel {
context.registerMappedSuperclassType( mappedSuperclass, mappedSuperclassType );
return mappedSuperclassType;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Serialization
private Object writeReplace() throws ObjectStreamException {
return new SerialForm( typeConfiguration.getSessionFactory() );
}
private static class SerialForm implements Serializable {
private final SessionFactoryImplementor sessionFactory;
public SerialForm(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
private Object readResolve() {
return sessionFactory.getJpaMetamodel();
}
}
}

View File

@ -9,6 +9,7 @@ package org.hibernate.metamodel.model.domain.internal;
import java.util.List;
import org.hibernate.metamodel.internal.MetadataContext;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.hql.spi.SqmCreationState;
@ -44,6 +45,20 @@ class ListAttributeImpl<X, E> extends AbstractPluralAttribute<X, List<E>, E> imp
return indexPathSource;
}
@Override
public SqmPathSource<?> findSubPathSource(String name) {
final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact( name );
if ( nature != null ) {
switch ( nature ) {
case INDEX:
return indexPathSource;
case ELEMENT:
return getElementPathSource();
}
}
return getElementPathSource().findSubPathSource( name );
}
@Override
public SqmAttributeJoin createSqmJoin(
SqmFrom lhs,

View File

@ -55,6 +55,20 @@ class MapAttributeImpl<X, K, V> extends AbstractPluralAttribute<X, Map<K, V>, V>
return getKeyPathSource();
}
@Override
public SqmPathSource<?> findSubPathSource(String name) {
final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact( name );
if ( nature != null ) {
switch ( nature ) {
case INDEX:
return keyPathSource;
case ELEMENT:
return getElementPathSource();
}
}
return getElementPathSource().findSubPathSource( name );
}
@Override
public SimpleDomainType<K> getKeyType() {
return (SimpleDomainType<K>) keyPathSource.getSqmPathType();

View File

@ -7,7 +7,6 @@
package org.hibernate.metamodel.model.domain.internal;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.query.sqm.IllegalPathUsageException;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
@ -31,7 +30,7 @@ public class NonAggregatedCompositeSqmPathSource extends AbstractSqmPathSource i
}
@Override
public SqmPathSource<?> findSubPathSource(String name) throws IllegalPathUsageException {
public SqmPathSource<?> findSubPathSource(String name) {
return (SqmPathSource<?>) getSqmPathType().findAttribute( name );
}

View File

@ -221,7 +221,7 @@ public class SingularAttributeImpl<D,J>
}
@Override
public SqmPath<J> createSqmPath(SqmPath lhs) {
public SqmPath<J> createSqmPath(SqmPath<?> lhs) {
return sqmPathSource.createSqmPath( lhs );
}

View File

@ -1289,30 +1289,6 @@ public abstract class AbstractEntityPersister
tableGroup,
creationState
);
if ( discriminatorMapping != null ) {
discriminatorMapping.applySqlSelections(
navigablePath.append( discriminatorMapping.getPartName() ),
tableGroup,
creationState
);
}
if ( versionMapping != null ) {
versionMapping.applySqlSelections(
navigablePath.append( versionMapping.getPartName() ),
tableGroup,
creationState
);
}
for ( int i = 0; i < attributeMappings.size(); i++ ) {
final AttributeMapping attributeMapping = attributeMappings.get( i );
if ( attributeMapping instanceof SingularAttributeMapping ) {
attributeMapping.applySqlSelections(
navigablePath.append( attributeMapping.getPartName() ),
tableGroup,
creationState
);
}
}
}
@Override
@ -1327,33 +1303,6 @@ public abstract class AbstractEntityPersister
creationState,
selectionConsumer
);
if ( discriminatorMapping != null ) {
discriminatorMapping.applySqlSelections(
navigablePath.append( discriminatorMapping.getPartName() ),
tableGroup,
creationState,
selectionConsumer
);
}
if ( versionMapping != null ) {
versionMapping.applySqlSelections(
navigablePath.append( versionMapping.getPartName() ),
tableGroup,
creationState,
selectionConsumer
);
}
for ( int i = 0; i < attributeMappings.size(); i++ ) {
final AttributeMapping attributeMapping = attributeMappings.get( i );
if ( attributeMapping instanceof SingularAttributeMapping ) {
attributeMapping.applySqlSelections(
navigablePath.append( attributeMapping.getPartName() ),
tableGroup,
creationState,
selectionConsumer
);
}
}
}
@Override

View File

@ -87,7 +87,7 @@ public enum ComparisonOperator {
@Override
public String sqlText() {
return "is not distinct from";
return " is not distinct from ";
}
},
@ -114,7 +114,7 @@ public enum ComparisonOperator {
@Override
public String sqlText() {
return "is distinct from";
return " is distinct from ";
}
},

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.query;
import java.io.Serializable;
import org.hibernate.internal.util.StringHelper;
/**
@ -14,7 +16,7 @@ import org.hibernate.internal.util.StringHelper;
*
* @author Steve Ebersole
*/
public class NavigablePath implements DotIdentifierSequence {
public class NavigablePath implements DotIdentifierSequence, Serializable {
public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper";
private final NavigablePath parent;

View File

@ -11,6 +11,7 @@ import java.util.function.Consumer;
import javax.persistence.Parameter;
import org.hibernate.Incubating;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
/**
@ -57,6 +58,10 @@ public interface ParameterMetadata {
*/
QueryParameter<?> resolve(Parameter param);
default <T> AllowableParameterType<T> getInferredParameterType(QueryParameter<T> parameter) {
return null;
}
/**
* Is this parameter reference registered in this collection?
*/

View File

@ -145,6 +145,9 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
JpaCompoundSelection<Object[]> array(Selection<?>[] selections);
JpaCompoundSelection<Object[]> array(List<? extends JpaSelection<?>> selections);
<Y> JpaCompoundSelection<Y> array(Class<Y> resultClass, Selection<?>[] selections);
<Y> JpaCompoundSelection<Y> array(Class<Y> resultClass, List<? extends JpaSelection<?>> selections);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Expressions
@ -272,6 +275,8 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@Override
<T> JpaParameterExpression<T> parameter(Class<T> paramClass, String name);
<T> JpaParameterExpression<T> parameter(Class<T> paramClass, T value);
@Override
JpaExpression<String> concat(Expression<String> x, Expression<String> y);
@ -423,13 +428,12 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
* @apiNote This is different from the purely JPA form
* {@link CriteriaBuilder#tuple} which is intended only for use as
* the selection in a root query.
*
* @param tupleType The Java type
*@param tupleType The Java type
* @param expressions The individual expressions making up the tuple
*/
<R> JpaCompoundSelection<R> tuple(
Class<R> tupleType,
List<JpaExpression<?>> expressions);
List<? extends JpaExpression<?>> expressions);
/**
* Create a tuple, as in a composite value, usable in any
@ -459,7 +463,7 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
*/
<R> JpaCompoundSelection<R> tuple(
DomainType<R> tupleType,
List<JpaExpression<?>> expressions);
List<? extends JpaExpression<?>> expressions);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -671,7 +675,7 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@SuppressWarnings("unchecked")
<T> JpaInPredicate<T> in(Expression<? extends T> expression, T... values);
<T> JpaInPredicate<T> in(Expression<? extends T> expression, List<T> values);
<T> JpaInPredicate<T> in(Expression<? extends T> expression, Collection<T> values);
@Override
JpaPredicate exists(Subquery<?> subquery);
@ -724,7 +728,7 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
*
* @return size expression
*/
<M extends Map<?,?>> JpaExpression<Integer> mapSize(M map);
<M extends Map<?, ?>> JpaExpression<Integer> mapSize(M map);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -6,7 +6,13 @@
*/
package org.hibernate.query.criteria;
import java.util.Collection;
import java.util.Map;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.metamodel.MapAttribute;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.NavigablePath;
@ -46,4 +52,19 @@ public interface JpaPath<T> extends JpaExpression<T>, Path<T> {
default JpaPath<?> getParentPath() {
return getLhs();
}
@Override
<Y> JpaPath<Y> get(SingularAttribute<? super T, Y> attribute);
@Override
<E, C extends Collection<E>> JpaExpression<C> get(PluralAttribute<T, C, E> collection);
@Override
<K, V, M extends Map<K, V>> JpaExpression<M> get(MapAttribute<T, K, V> map);
@Override
JpaExpression<Class<? extends T>> type();
@Override
<Y> JpaPath<Y> get(String attributeName);
}

View File

@ -289,6 +289,7 @@ public class QuerySplitter {
final SqmRoot<?> copy = new SqmRoot<>(
pathSource,
sqmRoot.getExplicitAlias(),
sqmRoot.isAllowJoins(),
sqmRoot.nodeBuilder()
);
return (SqmRoot<?>) getProcessingStateStack().getCurrent().getPathRegistry().resolvePath(
@ -632,7 +633,7 @@ public class QuerySplitter {
@Override
public SqmPositionalParameter visitPositionalParameterExpression(SqmPositionalParameter expression) {
public SqmPositionalParameter visitPositionalParameterExpression(SqmPositionalParameter<?> expression) {
return new SqmPositionalParameter(
expression.getPosition(),
expression.allowMultiValuedBinding(),
@ -641,7 +642,7 @@ public class QuerySplitter {
}
@Override
public SqmNamedParameter visitNamedParameterExpression(SqmNamedParameter expression) {
public SqmNamedParameter visitNamedParameterExpression(SqmNamedParameter<?> expression) {
return new SqmNamedParameter(
expression.getName(),
expression.allowMultiValuedBinding(),
@ -650,12 +651,12 @@ public class QuerySplitter {
}
@Override
public SqmLiteralEntityType visitEntityTypeLiteralExpression(SqmLiteralEntityType expression) {
public SqmLiteralEntityType visitEntityTypeLiteralExpression(SqmLiteralEntityType<?> expression) {
return new SqmLiteralEntityType( expression.getNodeType(), expression.nodeBuilder() );
}
@Override
public SqmUnaryOperation visitUnaryOperationExpression(SqmUnaryOperation expression) {
public SqmUnaryOperation visitUnaryOperationExpression(SqmUnaryOperation<?> expression) {
return new SqmUnaryOperation(
expression.getOperation(),
(SqmExpression) expression.getOperand().accept( this )
@ -672,7 +673,7 @@ public class QuerySplitter {
}
@Override
public SqmBinaryArithmetic visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) {
public SqmBinaryArithmetic visitBinaryArithmeticExpression(SqmBinaryArithmetic<?> expression) {
return new SqmBinaryArithmetic(
expression.getOperator(), (SqmExpression) expression.getLeftHandOperand().accept( this ),
(SqmExpression) expression.getRightHandOperand().accept( this ),
@ -682,7 +683,7 @@ public class QuerySplitter {
}
@Override
public SqmSubQuery visitSubQueryExpression(SqmSubQuery expression) {
public SqmSubQuery visitSubQueryExpression(SqmSubQuery<?> expression) {
// its not supported for a SubQuery to define a dynamic instantiation, so
// any "selectable node" will only ever be an SqmExpression
return new SqmSubQuery(

View File

@ -43,6 +43,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.CollectionPart;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.DomainType;
@ -54,6 +55,7 @@ import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
import org.hibernate.query.BinaryArithmeticOperator;
import org.hibernate.query.ComparisonOperator;
import org.hibernate.query.FetchClauseType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.NullPrecedence;
import org.hibernate.query.PathException;
import org.hibernate.query.SemanticException;
@ -403,6 +405,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return new SqmRoot<>(
(EntityDomainType<R>) visitEntityName( entityNameContext ),
identificationVariable,
false,
creationContext.getNodeBuilder()
);
}
@ -852,7 +855,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
fromClause.visitRoots(
sqmRoot -> selectClause.addSelection(
new SqmSelection<>( sqmRoot, sqmRoot.getExplicitAlias(), creationContext.getNodeBuilder() )
new SqmSelection<>( sqmRoot, sqmRoot.getAlias(), creationContext.getNodeBuilder() )
)
);
return selectClause;
@ -952,8 +955,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
);
}
final PluralPersistentAttribute<?, ?, ?> pluralAttribute = (PluralPersistentAttribute<?, ?, ?>) sqmPath.getReferencedPathSource();
final SqmPath<?> elementPath = pluralAttribute.getElementPathSource().createSqmPath( sqmPath );
final SqmPath<?> elementPath = (SqmPath<?>) sqmPath.resolvePathPart( CollectionPart.Nature.ELEMENT.getName(), true, this );
processingStateStack.getCurrent().getPathRegistry().register( elementPath );
return elementPath;
}
@ -1534,7 +1536,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
}
}
final SqmRoot<?> sqmRoot = new SqmRoot<>( entityDescriptor, alias, creationContext.getNodeBuilder() );
final SqmRoot<?> sqmRoot = new SqmRoot<>( entityDescriptor, alias, true, creationContext.getNodeBuilder() );
pathRegistry.register( sqmRoot );
@ -1688,7 +1690,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
}
else {
if ( getCreationOptions().useStrictJpaCompliance() ) {
if ( join.getExplicitAlias() != null ){
if ( join.getExplicitAlias() != null ) {
//noinspection rawtypes
if ( ( (SqmAttributeJoin) join ).isFetched() ) {
throw new StrictJpaComplianceViolation(
@ -2158,13 +2160,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmPath<?> visitEntityIdReference(HqlParser.EntityIdReferenceContext ctx) {
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPath<Object> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
if ( sqmPathType instanceof IdentifiableDomainType<?> ) {
//noinspection unchecked
final SqmPath<?> idPath = ( (IdentifiableDomainType<?>) sqmPathType ).getIdentifierDescriptor()
.createSqmPath( sqmPath );
final SqmPathSource<?> identifierDescriptor = ( (IdentifiableDomainType<?>) sqmPathType ).getIdentifierDescriptor();
final SqmPath<?> idPath = sqmPath.get( identifierDescriptor.getPathName() );
if ( ctx.getChildCount() != 5 ) {
return idPath;
@ -2184,12 +2185,13 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmPath<?> visitEntityVersionReference(HqlParser.EntityVersionReferenceContext ctx) {
final SqmPath<?> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPath<Object> sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final DomainType<?> sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType();
if ( sqmPathType instanceof IdentifiableDomainType<?> ) {
final IdentifiableDomainType<?> identifiableType = (IdentifiableDomainType<?>) sqmPathType;
final SingularPersistentAttribute<?, ?> versionAttribute = identifiableType.findVersionAttribute();
@SuppressWarnings("unchecked")
final IdentifiableDomainType<Object> identifiableType = (IdentifiableDomainType<Object>) sqmPathType;
final SingularPersistentAttribute<Object, ?> versionAttribute = identifiableType.findVersionAttribute();
if ( versionAttribute == null ) {
throw new SemanticException(
"`" + sqmPath.getNavigablePath().getFullPath() + "` resolved to an identifiable-type (`" +
@ -2197,7 +2199,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
);
}
return versionAttribute.createSqmPath( sqmPath );
return sqmPath.get( versionAttribute );
}
throw new SemanticException( "Path does not reference an identifiable-type : " + sqmPath.getNavigablePath().getFullPath() );
@ -3614,19 +3616,20 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
selectClause.setSelection( literal );
}
else {
final SqmPathSource<?> pathSource;
final String partName;
switch ( collectionReferenceCtx.getSymbol().getType() ) {
case HqlParser.ELEMENTS:
pathSource = attribute.getElementPathSource();
partName = CollectionPart.Nature.ELEMENT.getName();
break;
case HqlParser.INDICES:
pathSource = attribute.getIndexPathSource();
partName = CollectionPart.Nature.INDEX.getName();
break;
default:
throw new ParsingException( "Unexpected collection reference : " + collectionReferenceCtx.getText() );
}
subQuery.applyInferableType( pathSource.getSqmPathType() );
selectClause.setSelection( pathSource.createSqmPath( collectionJoin ) );
final SqmPath<?> path = collectionJoin.resolvePathPart( partName, true, this );
subQuery.applyInferableType( path.getNodeType() );
selectClause.setSelection( path );
}
final SqmQuerySpec<?> querySpec = subQuery.getQuerySpec();
querySpec.setFromClause( fromClause );
@ -3822,13 +3825,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmPathSource<?> pluralAttribute = sqmFrom.getReferencedPathSource();
if ( !( pluralAttribute instanceof PluralPersistentAttribute ) ) {
if ( !( pluralAttribute instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
throw new ParsingException( "Could not resolve identification variable [" + alias + "] as plural-attribute" );
}
return ( (PluralPersistentAttribute<?, ?, ?>) pluralAttribute ).getIndexPathSource().createSqmPath(
sqmFrom
);
return sqmFrom.resolvePathPart( CollectionPart.Nature.INDEX.getName(), true, this );
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
@ -4020,6 +4021,17 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final DotIdentifierConsumer consumer = dotIdentifierConsumerStack.pop();
final SqmExpression<?> indexExpression = (SqmExpression<?>) ctx.getChild( 1 ).accept( this );
final SqmAttributeJoin<?, ?> attributeJoin = (SqmAttributeJoin<?, ?>) consumer.getConsumedPart();
final NavigablePath navigablePath = attributeJoin.getNavigablePath().getParent().append(
attributeJoin.getNavigablePath().getLocalName(),
indexExpression.toHqlString()
);
// Reuse an existing indexed path join if possible
for ( SqmJoin<?, ?> sqmJoin : attributeJoin.getSqmJoins() ) {
if ( sqmJoin.getNavigablePath().getLocalName().equals( navigablePath.getLocalName() ) ) {
return sqmJoin;
}
}
final SqmExpression<?> index;
if ( attributeJoin instanceof SqmListJoin<?, ?> ) {
index = ( (SqmListJoin<?, ?>) attributeJoin ).index();
@ -4032,6 +4044,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
}
attributeJoin.setJoinPredicate( creationContext.getNodeBuilder().equal( index, indexExpression ) );
final SqmIndexedCollectionAccessPath<?> path = new SqmIndexedCollectionAccessPath<>(
navigablePath,
attributeJoin,
indexExpression
);
@ -4118,7 +4131,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
final SqmPath<?> pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource();
if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) {
if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
throw new PathException(
"Illegal attempt to treat non-plural path as a plural path : " + pluralAttributePath.getNavigablePath()
);
@ -4130,11 +4143,13 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
if ( attribute.getCollectionClassification() != CollectionClassification.MAP ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.VALUE_FUNCTION_ON_NON_MAP );
}
final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 );
if ( firstNode.getSymbol().getType() == HqlParser.ELEMENTS ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
}
}
SqmPath<?> result = attribute.getElementPathSource().createSqmPath(
pluralAttributePath
);
SqmPath<?> result = (SqmPath<?>) pluralAttributePath.resolvePathPart( CollectionPart.Nature.ELEMENT.getName(), true, this );
if ( ctx.getChildCount() == 5 ) {
result = consumeDomainPath( (HqlParser.DotIdentifierSequenceContext) ctx.getChild( 4 ).getChild( 1 ) );
@ -4146,26 +4161,19 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
@Override
public SqmPath<?> visitCollectionIndexNavigablePath(HqlParser.CollectionIndexNavigablePathContext ctx) {
if ( getCreationOptions().useStrictJpaCompliance() ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION );
}
final SqmPath<?> pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) );
final SqmPathSource<?> referencedPathSource = pluralAttributePath.getReferencedPathSource();
if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) {
if ( !(referencedPathSource instanceof PluralPersistentAttribute<?, ?, ?> ) ) {
throw new PathException(
"Illegal attempt to treat non-plural path as a plural path : " + pluralAttributePath.getNavigablePath()
);
}
final PluralPersistentAttribute<?, ?, ?> attribute = (PluralPersistentAttribute<?, ?, ?>) referencedPathSource;
if ( getCreationOptions().useStrictJpaCompliance() ) {
if ( attribute.getCollectionClassification() != CollectionClassification.MAP ) {
throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.VALUE_FUNCTION_ON_NON_MAP );
}
}
return attribute.getIndexPathSource().createSqmPath(
pluralAttributePath
);
return (SqmPath<?>) pluralAttributePath.resolvePathPart( CollectionPart.Nature.INDEX.getName(), true, this );
}
@Override
@ -4176,16 +4184,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
SqmPath<?> result;
if ( sqmPath instanceof SqmMapJoin ) {
final SqmMapJoin<?, ?, ?> sqmMapJoin = (SqmMapJoin<?, ?, ?>) sqmPath;
result = sqmMapJoin.getReferencedPathSource().getIndexPathSource().createSqmPath( sqmMapJoin );
result = sqmMapJoin.key();
}
else {
assert sqmPath instanceof SqmPluralValuedSimplePath;
final SqmPluralValuedSimplePath<?> mapPath = (SqmPluralValuedSimplePath<?>) sqmPath;
final SqmPath<?> keyPath = mapPath.getReferencedPathSource()
.getIndexPathSource()
.createSqmPath( mapPath );
mapPath.registerReusablePath( keyPath );
result = keyPath;
result = mapPath.resolvePathPart( CollectionPart.Nature.INDEX.getName(), true, this );
}
if ( ctx.getChildCount() == 5 ) {
@ -4195,10 +4199,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return result;
}
private SqmPath<?> consumeDomainPath(HqlParser.PathContext parserPath) {
private <X> SqmPath<X> consumeDomainPath(HqlParser.PathContext parserPath) {
final SemanticPathPart consumedPart = (SemanticPathPart) parserPath.accept( this );
if ( consumedPart instanceof SqmPath ) {
return (SqmPath<?>) consumedPart;
//noinspection unchecked
return (SqmPath<X>) consumedPart;
}
throw new SemanticException( "Expecting domain-model path, but found : " + consumedPart );

View File

@ -37,12 +37,12 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
private final SqmCreationProcessingState associatedProcessingState;
private final JpaCompliance jpaCompliance;
private final Map<NavigablePath, SqmPath> sqmPathByPath = new HashMap<>();
private final Map<NavigablePath, SqmFrom> sqmFromByPath = new HashMap<>();
private final Map<NavigablePath, SqmPath<?>> sqmPathByPath = new HashMap<>();
private final Map<NavigablePath, SqmFrom<?, ?>> sqmFromByPath = new HashMap<>();
private final Map<String, SqmFrom> sqmFromByAlias = new HashMap<>();
private final Map<String, SqmFrom<?, ?>> sqmFromByAlias = new HashMap<>();
private final List<SqmAliasedNode> simpleSelectionNodes = new ArrayList<>();
private final List<SqmAliasedNode<?>> simpleSelectionNodes = new ArrayList<>();
public SqmPathRegistryImpl(SqmCreationProcessingState associatedProcessingState) {
this.associatedProcessingState = associatedProcessingState;
@ -50,7 +50,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
}
@Override
public void register(SqmPath sqmPath) {
public void register(SqmPath<?> sqmPath) {
SqmTreeCreationLogger.LOGGER.tracef( "SqmProcessingIndex#register(SqmPath) : %s", sqmPath.getNavigablePath().getFullPath() );
// Generally we:
@ -61,8 +61,8 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
// Regarding part #1 (add to the path-by-path map), it is ok for a SqmFrom to replace a
// non-SqmFrom. This should equate to, e.g., an implicit join.
if ( sqmPath instanceof SqmFrom ) {
final SqmFrom sqmFrom = (SqmFrom) sqmPath;
if ( sqmPath instanceof SqmFrom<?, ?> ) {
final SqmFrom<?, ?> sqmFrom = (SqmFrom<?, ?>) sqmPath;
final String alias = sqmPath.getExplicitAlias();
if ( alias != null ) {
@ -70,7 +70,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
? alias.toLowerCase( Locale.getDefault() )
: alias;
final SqmFrom previousFrom = sqmFromByAlias.put( aliasToUse, sqmFrom );
final SqmFrom<?, ?> previousFrom = sqmFromByAlias.put( aliasToUse, sqmFrom );
if ( previousFrom != null ) {
throw new AliasCollisionException(
@ -85,7 +85,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
}
}
final SqmFrom previousFromByPath = sqmFromByPath.put( sqmPath.getNavigablePath(), sqmFrom );
final SqmFrom<?, ?> previousFromByPath = sqmFromByPath.put( sqmPath.getNavigablePath(), sqmFrom );
if ( previousFromByPath != null ) {
// this should never happen
@ -101,7 +101,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
}
}
final SqmPath previousPath = sqmPathByPath.put( sqmPath.getNavigablePath(), sqmPath );
final SqmPath<?> previousPath = sqmPathByPath.put( sqmPath.getNavigablePath(), sqmPath );
if ( previousPath instanceof SqmFrom ) {
// this should never happen
@ -118,14 +118,15 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
}
@Override
public SqmPath findPath(NavigablePath path) {
final SqmPath found = sqmPathByPath.get( path );
public <X> SqmPath<X> findPath(NavigablePath path) {
final SqmPath<?> found = sqmPathByPath.get( path );
if ( found != null ) {
return found;
//noinspection unchecked
return (SqmPath<X>) found;
}
if ( associatedProcessingState.getParentProcessingState() != null ) {
final SqmFrom containingQueryFrom = associatedProcessingState.getParentProcessingState()
final SqmFrom<?, X> containingQueryFrom = associatedProcessingState.getParentProcessingState()
.getPathRegistry()
.findFromByPath( path );
if ( containingQueryFrom != null ) {
@ -138,14 +139,15 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
}
@Override
public SqmFrom findFromByPath(NavigablePath navigablePath) {
final SqmFrom found = sqmFromByPath.get( navigablePath );
public <X extends SqmFrom<?, ?>> X findFromByPath(NavigablePath navigablePath) {
final SqmFrom<?, ?> found = sqmFromByPath.get( navigablePath );
if ( found != null ) {
return found;
//noinspection unchecked
return (X) found;
}
if ( associatedProcessingState.getParentProcessingState() != null ) {
final SqmFrom containingQueryFrom = associatedProcessingState.getParentProcessingState()
final X containingQueryFrom = associatedProcessingState.getParentProcessingState()
.getPathRegistry()
.findFromByPath( navigablePath );
if ( containingQueryFrom != null ) {
@ -158,15 +160,16 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
}
@Override
public SqmFrom findFromByAlias(String alias) {
public <X extends SqmFrom<?, ?>> X findFromByAlias(String alias) {
final String localAlias = jpaCompliance.isJpaQueryComplianceEnabled()
? alias.toLowerCase( Locale.getDefault() )
: alias;
final SqmFrom registered = sqmFromByAlias.get( localAlias );
final SqmFrom<?, ?> registered = sqmFromByAlias.get( localAlias );
if ( registered != null ) {
return registered;
//noinspection unchecked
return (X) registered;
}
if ( associatedProcessingState.getParentProcessingState() != null ) {
@ -177,14 +180,14 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
}
@Override
public SqmFrom findFromExposing(String navigableName) {
public <X extends SqmFrom<?, ?>> X findFromExposing(String navigableName) {
// todo (6.0) : atm this checks every from-element every time, the idea being to make sure there
// is only one such element obviously that scales poorly across larger from-clauses. Another
// (configurable?) option would be to simply pick the first one as a perf optimization
SqmFrom found = null;
for ( Map.Entry<NavigablePath, SqmFrom> entry : sqmFromByPath.entrySet() ) {
final SqmFrom fromElement = entry.getValue();
SqmFrom<?, ?> found = null;
for ( Map.Entry<NavigablePath, SqmFrom<?, ?>> entry : sqmFromByPath.entrySet() ) {
final SqmFrom<?, ?> fromElement = entry.getValue();
if ( definesAttribute( fromElement.getReferencedPathSource(), navigableName ) ) {
if ( found != null ) {
throw new IllegalStateException( "Multiple from-elements expose unqualified attribute : " + navigableName );
@ -208,24 +211,26 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
navigableName
);
return found;
//noinspection unchecked
return (X) found;
}
@Override
public SqmPath resolvePath(NavigablePath navigablePath, Function<NavigablePath, SqmPath> creator) {
public <X> SqmPath<X> resolvePath(NavigablePath navigablePath, Function<NavigablePath, SqmPath<X>> creator) {
SqmTreeCreationLogger.LOGGER.tracef( "SqmProcessingIndex#resolvePath(NavigablePath) : %s", navigablePath );
final SqmPath existing = sqmPathByPath.get( navigablePath );
final SqmPath<?> existing = sqmPathByPath.get( navigablePath );
if ( existing != null ) {
return existing;
//noinspection unchecked
return (SqmPath<X>) existing;
}
final SqmPath sqmPath = creator.apply( navigablePath );
final SqmPath<X> sqmPath = creator.apply( navigablePath );
register( sqmPath );
return sqmPath;
}
private boolean definesAttribute(SqmPathSource containerType, String name) {
private boolean definesAttribute(SqmPathSource<?> containerType, String name) {
return containerType.findSubPathSource( name ) != null;
}
@ -282,7 +287,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
simpleSelectionNodes.add( node );
}
private void checkResultVariable(SqmAliasedNode selection) {
private void checkResultVariable(SqmAliasedNode<?> selection) {
final String alias = selection.getAlias();
if ( alias == null ) {
return;
@ -300,7 +305,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
);
}
final SqmFrom registeredFromElement = sqmFromByAlias.get( alias );
final SqmFrom<?, ?> registeredFromElement = sqmFromByAlias.get( alias );
if ( registeredFromElement != null ) {
if ( !registeredFromElement.equals( selection.getSelectableNode() ) ) {
throw new AliasCollisionException(

View File

@ -29,8 +29,8 @@ public interface SemanticPathPart {
boolean isTerminal,
SqmCreationState creationState);
SqmPath resolveIndexedAccess(
SqmExpression selector,
SqmPath<?> resolveIndexedAccess(
SqmExpression<?> selector,
boolean isTerminal,
SqmCreationState creationState);
}

View File

@ -30,7 +30,7 @@ public interface SqmPathRegistry {
/**
* Register an SqmPath
*/
void register(SqmPath sqmPath);
void register(SqmPath<?> sqmPath);
/**
* Find a SqmFrom by its identification variable (alias). Will search any
@ -38,14 +38,14 @@ public interface SqmPathRegistry {
*
* @return matching SqmFrom or {@code null}
*/
SqmFrom findFromByAlias(String identificationVariable);
<X extends SqmFrom<?, ?>> X findFromByAlias(String identificationVariable);
/**
* Find a SqmFrom by its NavigablePath. Will search any parent contexts as well
*
* @return matching SqmFrom or {@code null}
*/
SqmFrom findFromByPath(NavigablePath navigablePath);
<X extends SqmFrom<?, ?>> X findFromByPath(NavigablePath navigablePath);
/**
* Find a SqmFrom which exposes a Navigable by the given name. Will search any
@ -53,7 +53,7 @@ public interface SqmPathRegistry {
*
* @return matching SqmFrom or {@code null}
*/
SqmFrom findFromExposing(String navigableName);
<X extends SqmFrom<?, ?>> X findFromExposing(String navigableName);
/**
* Find an SqmPath by its NavigablePath. Will return a SqmFrom if the NavigablePath
@ -61,7 +61,7 @@ public interface SqmPathRegistry {
*
* @return matching SqmPath or {@code null}
*/
SqmPath findPath(NavigablePath path);
<X> SqmPath<X> findPath(NavigablePath path);
/**
* Similar to {@link #findPath}, but accepting a producer to be used
@ -69,7 +69,7 @@ public interface SqmPathRegistry {
*
* @return The existing or just-created SqmPath
*/
SqmPath resolvePath(NavigablePath path, Function<NavigablePath, SqmPath> creator);
<X> SqmPath<X> resolvePath(NavigablePath path, Function<NavigablePath, SqmPath<X>> creator);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -9,6 +9,7 @@ package org.hibernate.query.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@ -22,9 +23,11 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.internal.util.compare.ComparableComparator;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
/**
* Encapsulates metadata about parameters encountered within a query.
@ -37,19 +40,19 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
*/
public static final ParameterMetadataImpl EMPTY = new ParameterMetadataImpl();
private final Set<QueryParameterImplementor<?>> queryParameters;
private final Map<QueryParameterImplementor<?>, List<SqmParameter>> queryParameters;
private final Set<String> names;
private final Set<Integer> labels;
private ParameterMetadataImpl() {
this.queryParameters = Collections.emptySet();
this.queryParameters = Collections.emptyMap();
this.names = Collections.emptySet();
this.labels = Collections.emptySet();
}
public ParameterMetadataImpl(Set<QueryParameterImplementor<?>> queryParameters) {
public ParameterMetadataImpl(Map<QueryParameterImplementor<?>, List<SqmParameter>> queryParameters) {
this.queryParameters = queryParameters;
// if we have any ordinal parameters, make sure the numbers
@ -58,7 +61,7 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
Set<String> names = null;
Set<Integer> labels = null;
for ( QueryParameterImplementor<?> queryParameter : queryParameters ) {
for ( QueryParameterImplementor<?> queryParameter : queryParameters.keySet() ) {
if ( queryParameter.getPosition() != null ) {
if ( labels == null ) {
labels = new HashSet<>();
@ -90,14 +93,16 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
if ( CollectionHelper.isEmpty( positionalQueryParameters )
&& CollectionHelper.isEmpty( namedQueryParameters ) ) {
// no parameters
this.queryParameters = Collections.emptySet();
this.queryParameters = Collections.emptyMap();
this.names = Collections.emptySet();
this.labels = Collections.emptySet();
}
else {
this.queryParameters = new IdentitySet<>();
this.queryParameters = new IdentityHashMap<>();
if ( positionalQueryParameters != null ) {
this.queryParameters.addAll( positionalQueryParameters.values() );
for ( QueryParameterImplementor<?> value : positionalQueryParameters.values() ) {
this.queryParameters.put( value, Collections.emptyList() );
}
this.labels = positionalQueryParameters.keySet();
verifyOrdinalParamLabels( labels );
}
@ -105,7 +110,9 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
labels = null;
}
if ( namedQueryParameters != null ) {
this.queryParameters.addAll( namedQueryParameters.values() );
for ( QueryParameterImplementor<?> value : namedQueryParameters.values() ) {
this.queryParameters.put( value, Collections.emptyList() );
}
this.names = namedQueryParameters.keySet();
}
else {
@ -160,25 +167,34 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
return queryParameters.size();
}
@Override
public <T> AllowableParameterType<T> getInferredParameterType(QueryParameter<T> parameter) {
final List<SqmParameter> sqmParameters = queryParameters.get( parameter );
if ( sqmParameters == null || sqmParameters.isEmpty() ) {
return null;
}
return sqmParameters.get( 0 ).getNodeType();
}
@Override
public boolean containsReference(QueryParameter<?> parameter) {
//noinspection SuspiciousMethodCalls
return queryParameters.contains( parameter );
return queryParameters.containsKey( parameter );
}
@Override
public void visitParameters(Consumer<QueryParameterImplementor<?>> consumer) {
queryParameters.forEach( consumer );
queryParameters.keySet().forEach( consumer );
}
@Override
public Set<QueryParameterImplementor<?>> getRegistrations() {
return Collections.unmodifiableSet( queryParameters );
return Collections.unmodifiableSet( queryParameters.keySet() );
}
@Override
public boolean hasAnyMatching(Predicate<QueryParameterImplementor<?>> filter) {
for ( QueryParameterImplementor<?> queryParameter : queryParameters ) {
for ( QueryParameterImplementor<?> queryParameter : queryParameters.keySet() ) {
if ( filter.test( queryParameter ) ) {
return true;
}
@ -212,13 +228,20 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
@Override
public QueryParameterImplementor<?> getQueryParameter(String name) {
for ( QueryParameterImplementor<?> queryParameter : queryParameters ) {
for ( QueryParameterImplementor<?> queryParameter : queryParameters.keySet() ) {
if ( name.equals( queryParameter.getName() ) ) {
return queryParameter;
}
}
return null;
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Could not locate named parameter [%s], expecting one of [%s]",
name,
String.join( ", ", names )
)
);
}
@ -237,7 +260,7 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor {
@Override
public QueryParameterImplementor<?> getQueryParameter(int positionLabel) {
for ( QueryParameterImplementor<?> queryParameter : queryParameters ) {
for ( QueryParameterImplementor<?> queryParameter : queryParameters.keySet() ) {
if ( queryParameter.getPosition() != null && queryParameter.getPosition() == positionLabel ) {
return queryParameter;
}

View File

@ -20,6 +20,7 @@ import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
import org.hibernate.query.spi.QueryParameterBindingValidator;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.CoercionException;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
@ -128,19 +129,19 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
return false;
}
if ( value instanceof Collection ) {
setBindValues( (Collection) value );
return true;
}
if ( value.getClass().isArray() ) {
setBindValues( (Collection) Arrays.asList( (Object[]) value ) );
if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
//noinspection unchecked
setBindValues( (Collection<T>) value );
return true;
}
return false;
}
private boolean isRegisteredAsBasicType(Class<?> valueClass) {
return getTypeConfiguration().getBasicTypeForJavaType( valueClass ) != null;
}
private void bindValue(T value) {
this.isBound = true;
this.bindValue = value;
@ -186,7 +187,20 @@ public class QueryParameterBindingImpl<T> implements QueryParameterBinding<T>, J
}
if ( bindType != null ) {
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
try {
value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this );
}
catch ( CoercionException ex ) {
throw new IllegalArgumentException(
String.format(
"Parameter value [%s] did not match expected type [%s (%s)]",
value,
bindType.getTypeName(),
temporalTypePrecision == null ? "n/a" : temporalTypePrecision.name()
),
ex
);
}
}
else if ( queryParameter.getHibernateType() != null ) {
value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this );

View File

@ -22,11 +22,13 @@ import org.hibernate.cache.spi.QueryKey;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypedExpressable;
import org.hibernate.type.spi.TypeConfiguration;
@ -106,7 +108,12 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
);
}
final QueryParameterBinding<T> binding = new QueryParameterBindingImpl<>( queryParameter, sessionFactory, null, queryParametersValidationEnabled );
final QueryParameterBinding<T> binding = new QueryParameterBindingImpl<>(
queryParameter,
sessionFactory,
parameterMetadata.getInferredParameterType( queryParameter ),
queryParametersValidationEnabled
);
parameterBindingMap.put( queryParameter, binding );
return binding;

View File

@ -73,6 +73,8 @@ public class QueryEngine {
final SqmTranslatorFactory sqmTranslatorFactory = resolveSqmTranslatorFactory( queryEngineOptions, dialect );
return new QueryEngine(
sessionFactory.getUuid(),
sessionFactory.getName(),
() -> sessionFactory.getRuntimeMetamodels().getJpaMetamodel(),
sessionFactory.getSessionFactoryOptions().getCriteriaValueHandlingMode(),
sessionFactory.getSessionFactoryOptions().getPreferredSqlTypeCodeForBoolean(),
@ -99,6 +101,8 @@ public class QueryEngine {
private final int preferredSqlTypeCodeForBoolean;
public QueryEngine(
String uuid,
String name,
Supplier<JpaMetamodel> jpaMetamodelAccess,
ValueHandlingMode criteriaValueHandlingMode,
int preferredSqlTypeCodeForBoolean,
@ -118,6 +122,8 @@ public class QueryEngine {
this.hqlTranslator = hqlTranslator;
this.criteriaBuilder = new SqmCriteriaNodeBuilder(
uuid,
name,
this,
jpaMetamodelAccess,
serviceRegistry,
@ -152,6 +158,8 @@ public class QueryEngine {
* Simplified constructor mainly meant for Quarkus use
*/
public QueryEngine(
String uuid,
String name,
JpaMetamodel jpaMetamodel,
ValueHandlingMode criteriaValueHandlingMode,
int preferredSqlTypeCodeForBoolean,
@ -170,6 +178,8 @@ public class QueryEngine {
dialect.initializeFunctionRegistry( this );
this.criteriaBuilder = new SqmCriteriaNodeBuilder(
uuid,
name,
this,
() -> jpaMetamodel,
serviceRegistry,

View File

@ -1,25 +0,0 @@
/*
* 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;
import org.hibernate.query.SemanticException;
/**
* Indicates an attempt to use an SqmPath in an unsupported manner - e.g., an
* attempt to de-reference a basic value
*
* @author Steve Ebersole
*/
public class IllegalPathUsageException extends SemanticException {
public IllegalPathUsageException(String message) {
super( message );
}
public IllegalPathUsageException(String message, Exception cause) {
super( message, cause );
}
}

View File

@ -409,7 +409,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
@Override
<R> SqmTuple<R> tuple(
Class<R> tupleType,
List<JpaExpression<?>> expressions);
List<? extends JpaExpression<?>> expressions);
@Override
<R> SqmTuple<R> tuple(
@ -419,7 +419,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
@Override
<R> SqmTuple<R> tuple(
DomainType<R> tupleType,
List<JpaExpression<?>> expressions);
List<? extends JpaExpression<?>> expressions);
@Override
SqmPredicate and(Expression<Boolean> x, Expression<Boolean> y);
@ -603,7 +603,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
<T> SqmInPredicate<T> in(Expression<? extends T> expression, T... values);
@Override
<T> SqmInPredicate<T> in(Expression<? extends T> expression, List<T> values);
<T> SqmInPredicate<T> in(Expression<? extends T> expression, Collection<T> values);
<T> SqmInPredicate<T> in(Expression<? extends T> expression, SqmSubQuery<T> subQuery);
@ -620,7 +620,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
<M extends Map<?,?>> SqmExpression<Integer> mapSize(JpaExpression<M> mapExpression);
@Override
SqmExpression<Integer> mapSize(Map map);
<M extends Map<?, ?>> SqmExpression<Integer> mapSize(M map);
@Override
SqmSortSpecification sort(

View File

@ -141,15 +141,15 @@ public interface SemanticQueryWalker<T> {
T visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path);
T visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path);
T visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath<?> path);
T visitEntityValuedPath(SqmEntityValuedSimplePath<?> path);
T visitPluralValuedPath(SqmPluralValuedSimplePath<?> path);
T visitSelfInterpretingSqmPath(SelfInterpretingSqmPath sqmPath);
T visitSelfInterpretingSqmPath(SelfInterpretingSqmPath<?> sqmPath);
T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path);
T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath<?> path);
T visitMaxElementPath(SqmMaxElementPath<?> path);
@ -161,7 +161,7 @@ public interface SemanticQueryWalker<T> {
T visitTreatedPath(SqmTreatedPath<?, ?> sqmTreatedPath);
T visitCorrelation(SqmCorrelation correlation);
T visitCorrelation(SqmCorrelation<?, ?> correlation);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -193,9 +193,9 @@ public interface SemanticQueryWalker<T> {
T visitLiteral(SqmLiteral<?> literal);
T visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral);
T visitEnumLiteral(SqmEnumLiteral<?> sqmEnumLiteral);
T visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral);
T visitFieldLiteral(SqmFieldLiteral<?> sqmFieldLiteral);
T visitTuple(SqmTuple<?> sqmTuple);
@ -229,27 +229,27 @@ public interface SemanticQueryWalker<T> {
T visitUnaryOperationExpression(SqmUnaryOperation<?> expression);
T visitFunction(SqmFunction tSqmFunction);
T visitFunction(SqmFunction<?> tSqmFunction);
T visitExtractUnit(SqmExtractUnit extractUnit);
T visitExtractUnit(SqmExtractUnit<?> extractUnit);
T visitFormat(SqmFormat sqmFormat);
T visitCastTarget(SqmCastTarget sqmCastTarget);
T visitCastTarget(SqmCastTarget<?> sqmCastTarget);
T visitTrimSpecification(SqmTrimSpecification trimSpecification);
T visitDistinct(SqmDistinct distinct);
T visitDistinct(SqmDistinct<?> distinct);
T visitStar(SqmStar sqmStar);
T visitCoalesce(SqmCoalesce sqmCoalesce);
T visitCoalesce(SqmCoalesce<?> sqmCoalesce);
T visitToDuration(SqmToDuration toDuration);
T visitToDuration(SqmToDuration<?> toDuration);
T visitByUnit(SqmByUnit sqmByUnit);
T visitDurationUnit(SqmDurationUnit durationUnit);
T visitDurationUnit(SqmDurationUnit<?> durationUnit);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// predicates
@ -306,7 +306,7 @@ public interface SemanticQueryWalker<T> {
T visitPluralAttributeSizeFunction(SqmCollectionSize function);
T visitMapEntryFunction(SqmMapEntryReference function);
T visitMapEntryFunction(SqmMapEntryReference<?, ?> function);
T visitFullyQualifiedClass(Class<?> namedClass);
}

View File

@ -11,6 +11,7 @@ import javax.persistence.metamodel.Bindable;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.tree.SqmExpressableAccessor;
import org.hibernate.query.sqm.tree.domain.SqmPath;
/**
@ -22,7 +23,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
*
* @author Steve Ebersole
*/
public interface SqmPathSource<J> extends SqmExpressable<J>, Bindable<J> {
public interface SqmPathSource<J> extends SqmExpressable<J>, Bindable<J>, SqmExpressableAccessor<J> {
/**
* The name of this thing. Mainly used in logging and when creating a
* {@link org.hibernate.query.NavigablePath}
@ -38,15 +39,20 @@ public interface SqmPathSource<J> extends SqmExpressable<J>, Bindable<J> {
/**
* Find a SqmPathSource by name relative to this source.
*
* @throws IllegalPathUsageException to indicate that this source cannot be de-referenced
* @throws IllegalStateException to indicate that this source cannot be de-referenced
*/
SqmPathSource<?> findSubPathSource(String name) throws IllegalPathUsageException;
SqmPathSource<?> findSubPathSource(String name);
/**
* Create an SQM path for this source relative to the given left-hand side
*/
SqmPath<J> createSqmPath(SqmPath<?> lhs);
@Override
default SqmExpressable<J> getExpressable() {
return (SqmExpressable<J>) getSqmPathType();
}
default <X extends DomainType> X sqmAs(Class<X> targetType) {
if ( targetType.isInstance( this ) ) {
//noinspection unchecked

View File

@ -113,7 +113,7 @@ public class NamedSqmFunctionDescriptor
boolean firstPass = true;
for ( SqlAstNode arg : sqlAstArguments ) {
if ( !firstPass ) {
sqlAppender.appendSql( ", " );
sqlAppender.appendSql( "," );
}
if ( caseWrapper && !( arg instanceof Distinct ) ) {
sqlAppender.appendSql( "case when " );

View File

@ -14,6 +14,7 @@ import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmAggregateFunction;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
@ -22,7 +23,8 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
/**
* @author Christian Beikov
*/
public class SelfRenderingSqmAggregateFunction<T> extends SelfRenderingSqmFunction<T> {
public class SelfRenderingSqmAggregateFunction<T> extends SelfRenderingSqmFunction<T>
implements SqmAggregateFunction<T> {
private final SqmPredicate filter;
@ -55,6 +57,11 @@ public class SelfRenderingSqmAggregateFunction<T> extends SelfRenderingSqmFuncti
);
}
@Override
public SqmPredicate getFilter() {
return filter;
}
@Override
public void appendHqlString(StringBuilder sb) {
final List<? extends SqmTypedNode<?>> arguments = getArguments();

View File

@ -12,6 +12,7 @@ import java.util.List;
import java.util.Map;
import javax.persistence.Tuple;
import javax.persistence.TupleElement;
import javax.persistence.criteria.CompoundSelection;
import org.hibernate.ScrollMode;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
@ -22,6 +23,7 @@ import org.hibernate.internal.EmptyScrollableResults;
import org.hibernate.internal.util.streams.StingArrayCollector;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterImplementor;
@ -32,6 +34,7 @@ import org.hibernate.query.sqm.sql.SqmTranslation;
import org.hibernate.query.sqm.sql.SqmTranslator;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.sql.ast.SqlAstTranslator;
@ -140,10 +143,22 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
if ( Tuple.class.isAssignableFrom( resultType ) ) {
// resultType is Tuple..
if ( queryOptions.getTupleTransformer() == null ) {
final Map<TupleElement<?>, Integer> tupleElementMap = new IdentityHashMap<>( selections.size() );
for ( int i = 0; i < selections.size(); i++ ) {
final SqmSelection<?> selection = selections.get( i );
tupleElementMap.put( selection.getSelectableNode(), i );
final Map<TupleElement<?>, Integer> tupleElementMap;
if ( selections.size() == 1 && selections.get( 0 ).getSelectableNode() instanceof CompoundSelection<?> ) {
final List<? extends JpaSelection<?>> selectionItems = selections.get( 0 )
.getSelectableNode()
.getSelectionItems();
tupleElementMap = new IdentityHashMap<>( selectionItems.size() );
for ( int i = 0; i < selectionItems.size(); i++ ) {
tupleElementMap.put( selectionItems.get( i ), i );
}
}
else {
tupleElementMap = new IdentityHashMap<>( selections.size() );
for ( int i = 0; i < selections.size(); i++ ) {
final SqmSelection<?> selection = selections.get( i );
tupleElementMap.put( selection.getSelectableNode(), i );
}
}
return (RowTransformer<R>) new RowTransformerJpaTupleImpl( new TupleMetadata( tupleElementMap ) );
}

Some files were not shown because too many files have changed in this diff Show More