Skip to content

Commit f43caf1

Browse files
committed
HHH-18661 Add unnest() set-returning function and enable XML/JSON based array support on more databases
1 parent 1568c52 commit f43caf1

File tree

159 files changed

+6396
-599
lines changed

Some content is hidden

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

159 files changed

+6396
-599
lines changed

docker_db.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ use master
434434
go
435435
create login $SYBASE_USER with password $SYBASE_PASSWORD
436436
go
437+
exec sp_configure 'enable xml', 1
438+
go
437439
exec sp_dboption $SYBASE_DB, 'abort tran on log full', true
438440
go
439441
exec sp_dboption $SYBASE_DB, 'allow nulls by default', true

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
import static org.hibernate.type.SqlTypes.INET;
9393
import static org.hibernate.type.SqlTypes.INTEGER;
9494
import static org.hibernate.type.SqlTypes.JSON;
95-
import static org.hibernate.type.SqlTypes.JSON_ARRAY;
9695
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
9796
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
9897
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
@@ -263,11 +262,9 @@ protected void registerColumnTypes(TypeContributions typeContributions, ServiceR
263262
if ( getVersion().isSameOrAfter( 20 ) ) {
264263
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( INET, "inet", this ) );
265264
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "jsonb", this ) );
266-
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON_ARRAY, "jsonb", this ) );
267265
}
268266
else {
269267
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "json", this ) );
270-
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON_ARRAY, "json", this ) );
271268
}
272269
ddlTypeRegistry.addDescriptor( new NamedNativeEnumDdlTypeImpl( this ) );
273270
ddlTypeRegistry.addDescriptor( new NamedNativeOrdinalEnumDdlTypeImpl( this ) );
@@ -372,23 +369,23 @@ protected void contributeCockroachTypes(TypeContributions typeContributions, Ser
372369
if ( getVersion().isSameOrAfter( 20, 0 ) ) {
373370
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) );
374371
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) );
375-
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbArrayJdbcType( serviceRegistry ) );
372+
jdbcTypeRegistry.addTypeConstructor( PgJdbcHelper.getJsonbArrayJdbcType( serviceRegistry ) );
376373
}
377374
else {
378375
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonJdbcType( serviceRegistry ) );
379-
jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonArrayJdbcType( serviceRegistry ) );
376+
jdbcTypeRegistry.addTypeConstructor( PgJdbcHelper.getJsonArrayJdbcType( serviceRegistry ) );
380377
}
381378
}
382379
else {
383380
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE );
384381
if ( getVersion().isSameOrAfter( 20, 0 ) ) {
385382
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE );
386383
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSONB_INSTANCE );
387-
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonArrayJdbcType.JSONB_INSTANCE );
384+
jdbcTypeRegistry.addTypeConstructor( PostgreSQLCastingJsonArrayJdbcTypeConstructor.JSONB_INSTANCE );
388385
}
389386
else {
390387
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSON_INSTANCE );
391-
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonArrayJdbcType.JSON_INSTANCE );
388+
jdbcTypeRegistry.addTypeConstructor( PostgreSQLCastingJsonArrayJdbcTypeConstructor.JSON_INSTANCE );
392389
}
393390
}
394391
}
@@ -398,11 +395,11 @@ protected void contributeCockroachTypes(TypeContributions typeContributions, Ser
398395
if ( getVersion().isSameOrAfter( 20, 0 ) ) {
399396
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE );
400397
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSONB_INSTANCE );
401-
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonArrayJdbcType.JSONB_INSTANCE );
398+
jdbcTypeRegistry.addTypeConstructor( PostgreSQLCastingJsonArrayJdbcTypeConstructor.JSONB_INSTANCE );
402399
}
403400
else {
404401
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSON_INSTANCE );
405-
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonArrayJdbcType.JSON_INSTANCE );
402+
jdbcTypeRegistry.addTypeConstructor( PostgreSQLCastingJsonArrayJdbcTypeConstructor.JSON_INSTANCE );
406403
}
407404
}
408405

@@ -518,6 +515,8 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
518515
functionFactory.jsonArrayAppend_postgresql( false );
519516
functionFactory.jsonArrayInsert_postgresql();
520517

518+
functionFactory.unnest( "unnest" );
519+
521520
// Postgres uses # instead of ^ for XOR
522521
functionContributions.getFunctionRegistry().patternDescriptorBuilder( "bitxor", "(?1#?2)" )
523522
.setExactArgumentCount( 2 )

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
8989
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
9090
import org.hibernate.type.JavaObjectType;
91+
import org.hibernate.type.SqlTypes;
9192
import org.hibernate.type.StandardBasicTypes;
9293
import org.hibernate.type.descriptor.ValueExtractor;
9394
import org.hibernate.type.descriptor.java.JavaType;
@@ -455,6 +456,14 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
455456
functionFactory.xmlexists_db2_legacy();
456457
}
457458
functionFactory.xmlagg();
459+
460+
functionFactory.unnest_emulated();
461+
}
462+
463+
@Override
464+
public int getPreferredSqlTypeCodeForArray() {
465+
// Even if DB2 11 supports JSON functions, it's not possible to unnest a JSON array to rows, so stick to XML
466+
return SqlTypes.XML_ARRAY;
458467
}
459468

460469
@Override

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.hibernate.sql.ast.tree.expression.Literal;
2929
import org.hibernate.sql.ast.tree.expression.SqlTuple;
3030
import org.hibernate.sql.ast.tree.expression.Summarization;
31+
import org.hibernate.sql.ast.tree.from.DerivedTableReference;
32+
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
3133
import org.hibernate.sql.ast.tree.from.NamedTableReference;
3234
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
3335
import org.hibernate.sql.ast.tree.from.TableGroup;
@@ -253,6 +255,17 @@ public void visitQueryPartTableReference(QueryPartTableReference tableReference)
253255
inLateral = oldLateral;
254256
}
255257

258+
@Override
259+
protected void renderDerivedTableReference(DerivedTableReference tableReference) {
260+
if ( tableReference instanceof FunctionTableReference && tableReference.isLateral() ) {
261+
// No need for a lateral keyword for functions
262+
tableReference.accept( this );
263+
}
264+
else {
265+
super.renderDerivedTableReference( tableReference );
266+
}
267+
}
268+
256269
@Override
257270
public void visitSelectStatement(SelectStatement statement) {
258271
if ( getQueryPartForRowNumbering() == statement.getQueryPart() && inLateral ) {

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

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@
44
*/
55
package org.hibernate.community.dialect;
66

7-
import org.hibernate.LockMode;
87
import org.hibernate.dialect.DatabaseVersion;
98
import org.hibernate.engine.spi.SessionFactoryImplementor;
109
import org.hibernate.query.sqm.ComparisonOperator;
1110
import org.hibernate.sql.ast.tree.Statement;
1211
import org.hibernate.sql.ast.tree.expression.Expression;
1312
import org.hibernate.sql.ast.tree.expression.Literal;
14-
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
15-
import org.hibernate.sql.ast.tree.from.NamedTableReference;
16-
import org.hibernate.sql.ast.tree.from.TableGroup;
17-
import org.hibernate.sql.ast.tree.from.TableReference;
13+
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
1814
import org.hibernate.sql.ast.tree.select.QueryPart;
1915
import org.hibernate.sql.exec.spi.JdbcOperation;
2016

@@ -58,28 +54,10 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp
5854
}
5955

6056
@Override
61-
protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
62-
if ( shouldInlineCte( tableGroup ) ) {
63-
inlineCteTableGroup( tableGroup, lockMode );
64-
return false;
65-
}
66-
final TableReference tableReference = tableGroup.getPrimaryTableReference();
67-
if ( tableReference instanceof NamedTableReference ) {
68-
return renderNamedTableReference( (NamedTableReference) tableReference, lockMode );
69-
}
57+
public void visitQueryPartTableReference(QueryPartTableReference tableReference) {
7058
// DB2 z/OS we need the "table" qualifier for table valued functions or lateral sub-queries
7159
append( "table " );
72-
tableReference.accept( this );
73-
return false;
74-
}
75-
76-
@Override
77-
public void visitFunctionTableReference(FunctionTableReference tableReference) {
78-
// For the table qualifier we need parenthesis on DB2 z/OS
79-
append( OPEN_PARENTHESIS );
80-
tableReference.getFunctionExpression().accept( this );
81-
append( CLOSE_PARENTHESIS );
82-
renderDerivedTableReference( tableReference );
60+
super.visitQueryPartTableReference( tableReference );
8361
}
8462

8563
@Override

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import org.hibernate.boot.model.FunctionContributions;
2020
import org.hibernate.boot.model.TypeContributions;
2121
import org.hibernate.dialect.*;
22+
import org.hibernate.dialect.aggregate.AggregateSupport;
23+
import org.hibernate.dialect.aggregate.H2AggregateSupport;
2224
import org.hibernate.dialect.function.CommonFunctionFactory;
2325
import org.hibernate.dialect.hint.IndexQueryHintHandler;
2426
import org.hibernate.dialect.identity.H2FinalTableIdentityColumnSupport;
@@ -97,7 +99,6 @@
9799
import static org.hibernate.type.SqlTypes.GEOMETRY;
98100
import static org.hibernate.type.SqlTypes.INTERVAL_SECOND;
99101
import static org.hibernate.type.SqlTypes.JSON;
100-
import static org.hibernate.type.SqlTypes.JSON_ARRAY;
101102
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
102103
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
103104
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
@@ -265,7 +266,6 @@ protected void registerColumnTypes(TypeContributions typeContributions, ServiceR
265266
}
266267
if ( getVersion().isSameOrAfter( 1, 4, 200 ) ) {
267268
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "json", this ) );
268-
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON_ARRAY, "json", this ) );
269269
}
270270
}
271271
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl( this ) );
@@ -296,12 +296,17 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
296296
}
297297
if ( getVersion().isSameOrAfter( 1, 4, 200 ) ) {
298298
jdbcTypeRegistry.addDescriptorIfAbsent( H2JsonJdbcType.INSTANCE );
299-
jdbcTypeRegistry.addDescriptorIfAbsent( H2JsonArrayJdbcType.INSTANCE );
299+
jdbcTypeRegistry.addTypeConstructor( H2JsonArrayJdbcTypeConstructor.INSTANCE );
300300
}
301301
jdbcTypeRegistry.addDescriptor( EnumJdbcType.INSTANCE );
302302
jdbcTypeRegistry.addDescriptor( OrdinalEnumJdbcType.INSTANCE );
303303
}
304304

305+
@Override
306+
public AggregateSupport getAggregateSupport() {
307+
return H2AggregateSupport.valueOf( this );
308+
}
309+
305310
@Override
306311
public int getDefaultStatementBatchSize() {
307312
return 15;
@@ -427,6 +432,8 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
427432
else {
428433
functionFactory.listagg_groupConcat();
429434
}
435+
436+
functionFactory.unnest_h2( getMaximumArraySize() );
430437
}
431438

432439
/**

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
277277
functionFactory.jsonObjectAgg_h2();
278278
}
279279

280+
functionFactory.unnest( "c1" );
281+
280282
//trim() requires parameters to be cast when used as trim character
281283
functionContributions.getFunctionRegistry().register( "trim", new TrimFunction(
282284
this,

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import org.hibernate.sql.ast.tree.expression.Literal;
2323
import org.hibernate.sql.ast.tree.expression.SqlTuple;
2424
import org.hibernate.sql.ast.tree.expression.Summarization;
25+
import org.hibernate.sql.ast.tree.from.DerivedTableReference;
26+
import org.hibernate.sql.ast.tree.from.FunctionTableReference;
2527
import org.hibernate.sql.ast.tree.from.NamedTableReference;
2628
import org.hibernate.sql.ast.tree.insert.ConflictClause;
2729
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
@@ -72,6 +74,17 @@ protected void renderDmlTargetTableExpression(NamedTableReference tableReference
7274
}
7375
}
7476

77+
@Override
78+
protected void renderDerivedTableReference(DerivedTableReference tableReference) {
79+
if ( tableReference instanceof FunctionTableReference && tableReference.isLateral() ) {
80+
// No need for a lateral keyword for functions
81+
tableReference.accept( this );
82+
}
83+
else {
84+
super.renderDerivedTableReference( tableReference );
85+
}
86+
}
87+
7588
@Override
7689
protected void visitConflictClause(ConflictClause conflictClause) {
7790
if ( conflictClause != null ) {

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.hibernate.type.SqlTypes;
3030
import org.hibernate.type.StandardBasicTypes;
3131
import org.hibernate.type.descriptor.jdbc.JdbcType;
32-
import org.hibernate.type.descriptor.jdbc.JsonArrayJdbcType;
3332
import org.hibernate.type.descriptor.jdbc.JsonJdbcType;
3433
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
3534
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
@@ -145,7 +144,6 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
145144
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration().getJdbcTypeRegistry();
146145
// Make sure we register the JSON type descriptor before calling super, because MariaDB does not need casting
147146
jdbcTypeRegistry.addDescriptorIfAbsent( SqlTypes.JSON, JsonJdbcType.INSTANCE );
148-
jdbcTypeRegistry.addDescriptorIfAbsent( SqlTypes.JSON_ARRAY, JsonArrayJdbcType.INSTANCE );
149147

150148
super.contributeTypes( typeContributions, serviceRegistry );
151149
if ( getVersion().isSameOrAfter( 10, 7 ) ) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.hibernate.sql.ast.tree.expression.Expression;
2323
import org.hibernate.sql.ast.tree.expression.Literal;
2424
import org.hibernate.sql.ast.tree.expression.Summarization;
25+
import org.hibernate.sql.ast.tree.from.DerivedTableReference;
2526
import org.hibernate.sql.ast.tree.from.NamedTableReference;
2627
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
2728
import org.hibernate.sql.ast.tree.insert.ConflictClause;
@@ -277,6 +278,11 @@ public void visitQueryPartTableReference(QueryPartTableReference tableReference)
277278
emulateQueryPartTableReferenceColumnAliasing( tableReference );
278279
}
279280

281+
@Override
282+
protected void renderDerivedTableReferenceIdentificationVariable(DerivedTableReference tableReference) {
283+
renderTableReferenceIdentificationVariable( tableReference );
284+
}
285+
280286
@Override
281287
public void visitOffsetFetchClause(QueryPart queryPart) {
282288
if ( !isRowNumberingCurrentQueryPart() ) {

0 commit comments

Comments
 (0)