Skip to content

Commit f55e274

Browse files
committed
HHH-3356 Support for normal and lateral subquery in from clause
1 parent a488e1a commit f55e274

File tree

56 files changed

+4584
-118
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+4584
-118
lines changed

hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ IS : [iI] [sS];
207207
JOIN : [jJ] [oO] [iI] [nN];
208208
KEY : [kK] [eE] [yY];
209209
LAST : [lL] [aA] [sS] [tT];
210+
LATERAL : [lL] [aA] [tT] [eE] [rR] [aA] [lL];
210211
LEADING : [lL] [eE] [aA] [dD] [iI] [nN] [gG];
211212
LEFT : [lL] [eE] [fF] [tT];
212213
LIKE : [lL] [iI] [kK] [eE];

hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,15 @@ fromClause
169169
* The declaration of a root entity in 'from' clause, along with its joins
170170
*/
171171
entityWithJoins
172-
: rootEntity (join | crossJoin | jpaCollectionJoin)*
172+
: fromRoot (join | crossJoin | jpaCollectionJoin)*
173173
;
174174

175175
/**
176176
* A root entity declaration in the 'from' clause, with optional identification variable
177177
*/
178-
rootEntity
179-
: entityName variable?
178+
fromRoot
179+
: entityName variable? # RootEntity
180+
| LATERAL? LEFT_PAREN subquery RIGHT_PAREN variable? # RootSubquery
180181
;
181182

182183
/**
@@ -212,7 +213,7 @@ jpaCollectionJoin
212213
* A 'join', with an optional 'on' or 'with' clause
213214
*/
214215
join
215-
: joinType JOIN FETCH? joinPath joinRestriction?
216+
: joinType JOIN FETCH? joinTarget joinRestriction?
216217
;
217218

218219
/**
@@ -226,8 +227,9 @@ joinType
226227
/**
227228
* The joined path, with an optional identification variable
228229
*/
229-
joinPath
230-
: path variable?
230+
joinTarget
231+
: path variable? #JoinPath
232+
| LATERAL? LEFT_PAREN subquery RIGHT_PAREN variable? #JoinSubquery
231233
;
232234

233235
/**

hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1081,7 +1081,8 @@ public boolean supportsValuesListForInsert() {
10811081

10821082
@Override
10831083
public boolean supportsOrderByInSubquery() {
1084-
return false;
1084+
// Seems to work, though I don't know as of which version
1085+
return true;
10851086
}
10861087

10871088
@Override

hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,8 @@ public boolean supportsTupleDistinctCounts() {
577577

578578
@Override
579579
public boolean supportsOrderByInSubquery() {
580-
return false;
580+
// As of version 10.5 Derby supports OFFSET and FETCH as well as ORDER BY in subqueries
581+
return getVersion().isSameOrAfter( 10, 5 );
581582
}
582583

583584
@Override

hibernate-core/src/main/java/org/hibernate/dialect/HANASqlAstTranslator.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
*/
3232
public class HANASqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
3333

34+
private boolean inLateral;
35+
3436
public HANASqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
3537
super( sessionFactory, statement );
3638
}
@@ -64,7 +66,20 @@ public void visitQuerySpec(QuerySpec querySpec) {
6466

6567
@Override
6668
public void visitQueryPartTableReference(QueryPartTableReference tableReference) {
67-
emulateQueryPartTableReferenceColumnAliasing( tableReference );
69+
if ( tableReference.isLateral() && !inLateral ) {
70+
inLateral = true;
71+
emulateQueryPartTableReferenceColumnAliasing( tableReference );
72+
inLateral = false;
73+
}
74+
else {
75+
emulateQueryPartTableReferenceColumnAliasing( tableReference );
76+
}
77+
}
78+
79+
@Override
80+
protected SqlAstNodeRenderingMode getParameterRenderingMode() {
81+
// HANA does not support parameters in lateral sub queries for some reason, so inline all the parameters in this case
82+
return inLateral ? SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS : super.getParameterRenderingMode();
6883
}
6984

7085
@Override

hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import java.util.function.Consumer;
1111

1212
import org.hibernate.engine.spi.SessionFactoryImplementor;
13+
import org.hibernate.metamodel.mapping.JdbcMapping;
14+
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
1315
import org.hibernate.query.sqm.BinaryArithmeticOperator;
1416
import org.hibernate.query.sqm.ComparisonOperator;
1517
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
@@ -213,10 +215,15 @@ protected void renderSelectTupleComparison(
213215
}
214216

215217
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
218+
final JdbcMappingContainer lhsExpressionType = lhs.getExpressionType();
219+
if ( lhsExpressionType == null ) {
220+
renderComparisonStandard( lhs, operator, rhs );
221+
return;
222+
}
216223
switch ( operator ) {
217224
case DISTINCT_FROM:
218225
case NOT_DISTINCT_FROM:
219-
if ( lhs.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType() instanceof ArrayJdbcType ) {
226+
if ( lhsExpressionType.getJdbcMappings().get( 0 ).getJdbcType() instanceof ArrayJdbcType ) {
220227
// HSQL implements distinct from semantics for arrays
221228
lhs.accept( this );
222229
appendSql( operator == ComparisonOperator.DISTINCT_FROM ? "<>" : "=" );

hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,17 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
132132
return false;
133133
}
134134

135+
@Override
136+
protected boolean supportsIntersect() {
137+
return getDialect().getVersion().isSameOrAfter( 10, 3 );
138+
}
139+
140+
@Override
141+
protected boolean supportsDistinctFromPredicate() {
142+
// It supports a proprietary operator
143+
return true;
144+
}
145+
135146
private boolean supportsWindowFunctions() {
136147
return getDialect().getVersion().isSameOrAfter( 10, 2 );
137148
}

hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,17 @@ protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
149149
return false;
150150
}
151151

152+
@Override
153+
protected boolean supportsIntersect() {
154+
return false;
155+
}
156+
157+
@Override
158+
protected boolean supportsDistinctFromPredicate() {
159+
// It supports a proprietary operator
160+
return true;
161+
}
162+
152163
@Override
153164
protected String getFromDual() {
154165
return " from dual";

hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.hibernate.engine.spi.SessionFactoryImplementor;
1212
import org.hibernate.internal.util.collections.Stack;
1313
import org.hibernate.metamodel.mapping.JdbcMapping;
14+
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
1415
import org.hibernate.query.sqm.BinaryArithmeticOperator;
1516
import org.hibernate.query.sqm.ComparisonOperator;
1617
import org.hibernate.query.sqm.FetchClauseType;
@@ -354,12 +355,12 @@ public void visitOver(Over<?> over) {
354355

355356
@Override
356357
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
357-
if ( lhs.getExpressionType() == null ) {
358+
final JdbcMappingContainer lhsExpressionType = lhs.getExpressionType();
359+
if ( lhsExpressionType == null ) {
358360
renderComparisonEmulateDecode( lhs, operator, rhs );
359361
return;
360362
}
361-
final JdbcMapping lhsMapping = lhs.getExpressionType().getJdbcMappings().get( 0 );
362-
switch ( lhsMapping.getJdbcType().getJdbcTypeCode() ) {
363+
switch ( lhsExpressionType.getJdbcMappings().get( 0 ).getJdbcType().getJdbcTypeCode() ) {
363364
case SqlTypes.SQLXML:
364365
// In Oracle, XMLTYPE is not "comparable", so we have to use the xmldiff function for this purpose
365366
switch ( operator ) {

hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/TupleType.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88

99
import java.util.List;
1010

11+
import org.hibernate.Incubating;
1112
import org.hibernate.query.sqm.SqmExpressible;
13+
import org.hibernate.sql.ast.spi.FromClauseAccess;
14+
import org.hibernate.sql.ast.spi.SqlSelection;
15+
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
1216

1317
/**
1418
* Describes any structural type without a direct java type representation.
@@ -23,4 +27,12 @@ public interface TupleType<J> extends SqmExpressible<J> {
2327

2428
SqmExpressible<?> get(int index);
2529
SqmExpressible<?> get(String componentName);
30+
31+
@Incubating
32+
default TableGroupProducer resolveTableGroupProducer(
33+
String aliasStem,
34+
List<SqlSelection> sqlSelections,
35+
FromClauseAccess fromClauseAccess) {
36+
return null;
37+
}
2638
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.metamodel.model.domain.internal;
8+
9+
import org.hibernate.Incubating;
10+
import org.hibernate.engine.spi.IdentifierValue;
11+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
12+
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
13+
import org.hibernate.metamodel.mapping.JdbcMapping;
14+
import org.hibernate.property.access.spi.PropertyAccess;
15+
import org.hibernate.query.sqm.SqmExpressible;
16+
17+
/**
18+
* @author Christian Beikov
19+
*/
20+
@Incubating
21+
public class AnonymousTupleBasicEntityIdentifierMapping extends AnonymousTupleBasicValuedModelPart
22+
implements BasicEntityIdentifierMapping {
23+
24+
private final BasicEntityIdentifierMapping delegate;
25+
26+
public AnonymousTupleBasicEntityIdentifierMapping(
27+
String selectionExpression,
28+
SqmExpressible<?> expressible,
29+
JdbcMapping jdbcMapping,
30+
BasicEntityIdentifierMapping delegate) {
31+
super( delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping );
32+
this.delegate = delegate;
33+
}
34+
35+
@Override
36+
public IdentifierValue getUnsavedStrategy() {
37+
return delegate.getUnsavedStrategy();
38+
}
39+
40+
@Override
41+
public Object getIdentifier(Object entity, SharedSessionContractImplementor session) {
42+
return delegate.getIdentifier( entity, session );
43+
}
44+
45+
@Override
46+
public Object getIdentifier(Object entity) {
47+
return delegate.getIdentifier( entity );
48+
}
49+
50+
@Override
51+
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
52+
delegate.setIdentifier( entity, id, session );
53+
}
54+
55+
@Override
56+
public Object instantiate() {
57+
return delegate.instantiate();
58+
}
59+
60+
@Override
61+
public PropertyAccess getPropertyAccess() {
62+
return delegate.getPropertyAccess();
63+
}
64+
65+
@Override
66+
public String getAttributeName() {
67+
return getPartName();
68+
}
69+
}

0 commit comments

Comments
 (0)