Skip to content

Commit 8036dd8

Browse files
committed
HHH-15328 Add support for CTE WITH clause
1 parent e59a736 commit 8036dd8

File tree

169 files changed

+6673
-1416
lines changed

Some content is hidden

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

169 files changed

+6673
-1416
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,6 @@ public void visitOffsetFetchClause(QueryPart queryPart) {
3737
renderCombinedLimitClause( queryPart );
3838
}
3939

40-
@Override
41-
protected void renderSearchClause(CteStatement cte) {
42-
// CUBRID does not support this, but it's just a hint anyway
43-
}
44-
45-
@Override
46-
protected void renderCycleClause(CteStatement cte) {
47-
// CUBRID does not support this, but it can be emulated
48-
}
49-
5040
@Override
5141
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
5242
renderComparisonEmulateIntersect( lhs, operator, rhs );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheSqlAstTranslator.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,6 @@ public void visitOffsetFetchClause(QueryPart queryPart) {
8080
}
8181
}
8282

83-
@Override
84-
protected void renderSearchClause(CteStatement cte) {
85-
// Cache does not support this, but it's just a hint anyway
86-
}
87-
88-
@Override
89-
protected void renderCycleClause(CteStatement cte) {
90-
// Cache does not support this, but it can be emulated
91-
}
92-
9383
@Override
9484
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
9585
renderComparisonEmulateIntersect( lhs, operator, rhs );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,11 @@ public boolean supportsNonQueryWithCTE() {
468468
return true;
469469
}
470470

471+
@Override
472+
public boolean supportsRecursiveCTE() {
473+
return getVersion().isSameOrAfter( 20, 1 );
474+
}
475+
471476
@Override
472477
public String getNoColumnsInsertString() {
473478
return "default values";

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacySqlAstTranslator.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.hibernate.engine.spi.SessionFactoryImplementor;
1010
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
1111
import org.hibernate.sql.ast.tree.Statement;
12+
import org.hibernate.sql.ast.tree.cte.CteMaterialization;
1213
import org.hibernate.sql.ast.tree.cte.CteStatement;
1314
import org.hibernate.sql.ast.tree.expression.Expression;
1415
import org.hibernate.sql.ast.tree.expression.Literal;
@@ -52,6 +53,26 @@ public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanEx
5253
}
5354
}
5455

56+
@Override
57+
protected void renderMaterializationHint(CteMaterialization materialization) {
58+
if ( getDialect().getVersion().isSameOrAfter( 20, 2 ) ) {
59+
if ( materialization == CteMaterialization.NOT_MATERIALIZED ) {
60+
appendSql( "not " );
61+
}
62+
appendSql( "materialized " );
63+
}
64+
}
65+
66+
@Override
67+
protected boolean supportsRowConstructor() {
68+
return true;
69+
}
70+
71+
@Override
72+
protected boolean supportsArrayConstructor() {
73+
return true;
74+
}
75+
5576
@Override
5677
protected String getForShare(int timeoutMillis) {
5778
return " for share";
@@ -116,16 +137,6 @@ public void visitOffsetFetchClause(QueryPart queryPart) {
116137
}
117138
}
118139

119-
@Override
120-
protected void renderSearchClause(CteStatement cte) {
121-
// Cockroach does not support this, but it's just a hint anyway
122-
}
123-
124-
@Override
125-
protected void renderCycleClause(CteStatement cte) {
126-
// Cockroach does not support this, but it can be emulated
127-
}
128-
129140
@Override
130141
protected void renderPartitionItem(Expression expression) {
131142
if ( expression instanceof Literal ) {

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,11 @@ public boolean supportsLockTimeouts() {
534534
return false;
535535
}
536536

537+
@Override
538+
public boolean requiresCastForConcatenatingNonStrings() {
539+
return true;
540+
}
541+
537542
@Override
538543
public String getSelectClauseNullString(int sqlType, TypeConfiguration typeConfiguration) {
539544
return selectNullString(sqlType);
@@ -756,6 +761,12 @@ public boolean supportsNonQueryWithCTE() {
756761
return true;
757762
}
758763

764+
@Override
765+
public boolean supportsRecursiveCTE() {
766+
// Supported at last since 9.7
767+
return getDB2Version().isSameOrAfter( 9, 7 );
768+
}
769+
759770
@Override
760771
public boolean supportsOffsetInSubquery() {
761772
return true;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.List;
1010
import java.util.function.Consumer;
1111

12+
import org.hibernate.LockMode;
1213
import org.hibernate.dialect.DatabaseVersion;
1314
import org.hibernate.engine.spi.SessionFactoryImplementor;
1415
import org.hibernate.query.sqm.ComparisonOperator;
@@ -26,6 +27,9 @@
2627
import org.hibernate.sql.ast.tree.expression.Literal;
2728
import org.hibernate.sql.ast.tree.expression.SqlTuple;
2829
import org.hibernate.sql.ast.tree.expression.Summarization;
30+
import org.hibernate.sql.ast.tree.from.TableGroup;
31+
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
32+
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
2933
import org.hibernate.sql.ast.tree.insert.InsertStatement;
3034
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
3135
import org.hibernate.sql.ast.tree.select.QueryGroup;
@@ -45,6 +49,70 @@ public DB2LegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, State
4549
super( sessionFactory, statement );
4650
}
4751

52+
@Override
53+
protected boolean needsRecursiveKeywordInWithClause() {
54+
return false;
55+
}
56+
57+
@Override
58+
protected boolean supportsWithClauseInSubquery() {
59+
return false;
60+
}
61+
62+
@Override
63+
protected void renderTableReferenceJoins(TableGroup tableGroup) {
64+
// When we are in a recursive CTE, we can't render joins on DB2...
65+
// See https://modern-sql.com/feature/with-recursive/db2/error-345-state-42836
66+
if ( isInRecursiveQueryPart() ) {
67+
final List<TableReferenceJoin> joins = tableGroup.getTableReferenceJoins();
68+
if ( joins == null || joins.isEmpty() ) {
69+
return;
70+
}
71+
72+
for ( TableReferenceJoin tableJoin : joins ) {
73+
switch ( tableJoin.getJoinType() ) {
74+
case CROSS:
75+
case INNER:
76+
break;
77+
default:
78+
throw new UnsupportedOperationException( "Can't emulate '" + tableJoin.getJoinType().getText() + "join' in a DB2 recursive query part" );
79+
}
80+
appendSql( COMA_SEPARATOR_CHAR );
81+
82+
renderNamedTableReference( tableJoin.getJoinedTableReference(), LockMode.NONE );
83+
84+
if ( tableJoin.getPredicate() != null && !tableJoin.getPredicate().isEmpty() ) {
85+
addAdditionalWherePredicate( tableJoin.getPredicate() );
86+
}
87+
}
88+
}
89+
else {
90+
super.renderTableReferenceJoins( tableGroup );
91+
}
92+
}
93+
94+
@Override
95+
protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {
96+
if ( isInRecursiveQueryPart() ) {
97+
switch ( tableGroupJoin.getJoinType() ) {
98+
case CROSS:
99+
case INNER:
100+
break;
101+
default:
102+
throw new UnsupportedOperationException( "Can't emulate '" + tableGroupJoin.getJoinType().getText() + "join' in a DB2 recursive query part" );
103+
}
104+
appendSql( COMA_SEPARATOR_CHAR );
105+
106+
renderTableGroup( tableGroupJoin.getJoinedGroup(), null, tableGroupJoinCollector );
107+
if ( tableGroupJoin.getPredicate() != null && !tableGroupJoin.getPredicate().isEmpty() ) {
108+
addAdditionalWherePredicate( tableGroupJoin.getPredicate() );
109+
}
110+
}
111+
else {
112+
super.renderTableGroupJoin( tableGroupJoin, tableGroupJoinCollector );
113+
}
114+
}
115+
48116
@Override
49117
protected void renderExpressionAsClauseItem(Expression expression) {
50118
expression.accept( this );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacyDialect.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ public boolean supportsLateral() {
123123
return getVersion().isSameOrAfter( 7, 1 );
124124
}
125125

126+
@Override
127+
public boolean supportsRecursiveCTE() {
128+
return getVersion().isSameOrAfter( 7, 1 );
129+
}
130+
126131
@Override
127132
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
128133
return new StandardSqlAstTranslatorFactory() {

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacyDialect.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ public boolean supportsLateral() {
125125
return true;
126126
}
127127

128+
@Override
129+
public boolean supportsRecursiveCTE() {
130+
return getVersion().isSameOrAfter( 11 );
131+
}
132+
128133
@Override
129134
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
130135
StringBuilder pattern = new StringBuilder();

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacySqlAstTranslator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp
6161

6262
@Override
6363
protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
64+
if ( shouldInlineCte( tableGroup ) ) {
65+
inlineCteTableGroup( tableGroup, lockMode );
66+
return false;
67+
}
6468
final TableReference tableReference = tableGroup.getPrimaryTableReference();
6569
if ( tableReference instanceof NamedTableReference ) {
6670
return renderNamedTableReference( (NamedTableReference) tableReference, lockMode );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.hibernate.dialect.RowLockStrategy;
1919
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
2020
import org.hibernate.dialect.function.CastingConcatFunction;
21+
import org.hibernate.dialect.function.ChrLiteralEmulation;
2122
import org.hibernate.dialect.function.CommonFunctionFactory;
2223
import org.hibernate.dialect.function.CountFunction;
2324
import org.hibernate.dialect.function.DerbyLpadEmulation;
@@ -286,6 +287,16 @@ public void initializeFunctionRegistry(QueryEngine queryEngine) {
286287
// AVG by default uses the input type, so we possibly need to cast the argument type, hence a special function
287288
functionFactory.avg_castingNonDoubleArguments( this, SqlAstNodeRenderingMode.DEFAULT );
288289

290+
// Note that Derby does not have chr() / ascii() functions.
291+
// It does have a function named char(), but it's really a
292+
// sort of to_char() function.
293+
294+
// We register an emulation instead, that can at least translate integer literals
295+
queryEngine.getSqmFunctionRegistry().register(
296+
"chr",
297+
new ChrLiteralEmulation( queryEngine.getTypeConfiguration() )
298+
);
299+
289300
functionFactory.concat_pipeOperator();
290301
functionFactory.cot();
291302
functionFactory.chr_char();
@@ -604,6 +615,11 @@ public boolean supportsOrderByInSubquery() {
604615
return getVersion().isSameOrAfter( 10, 5 );
605616
}
606617

618+
@Override
619+
public boolean requiresCastForConcatenatingNonStrings() {
620+
return true;
621+
}
622+
607623
@Override
608624
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
609625
super.contributeTypes( typeContributions, serviceRegistry );

0 commit comments

Comments
 (0)