Skip to content

Commit 384da42

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

File tree

182 files changed

+6329
-653
lines changed

Some content is hidden

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

182 files changed

+6329
-653
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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@
9797
import static org.hibernate.type.SqlTypes.GEOMETRY;
9898
import static org.hibernate.type.SqlTypes.INTERVAL_SECOND;
9999
import static org.hibernate.type.SqlTypes.JSON;
100-
import static org.hibernate.type.SqlTypes.JSON_ARRAY;
101100
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
102101
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
103102
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
@@ -265,7 +264,6 @@ protected void registerColumnTypes(TypeContributions typeContributions, ServiceR
265264
}
266265
if ( getVersion().isSameOrAfter( 1, 4, 200 ) ) {
267266
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON, "json", this ) );
268-
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( JSON_ARRAY, "json", this ) );
269267
}
270268
}
271269
ddlTypeRegistry.addDescriptor( new NativeEnumDdlTypeImpl( this ) );
@@ -296,7 +294,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
296294
}
297295
if ( getVersion().isSameOrAfter( 1, 4, 200 ) ) {
298296
jdbcTypeRegistry.addDescriptorIfAbsent( H2JsonJdbcType.INSTANCE );
299-
jdbcTypeRegistry.addDescriptorIfAbsent( H2JsonArrayJdbcType.INSTANCE );
297+
jdbcTypeRegistry.addTypeConstructor( H2JsonArrayJdbcTypeConstructor.INSTANCE );
300298
}
301299
jdbcTypeRegistry.addDescriptor( EnumJdbcType.INSTANCE );
302300
jdbcTypeRegistry.addDescriptor( OrdinalEnumJdbcType.INSTANCE );
@@ -427,6 +425,8 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
427425
else {
428426
functionFactory.listagg_groupConcat();
429427
}
428+
429+
functionFactory.unnest_h2( getMaximumArraySize() );
430430
}
431431

432432
/**

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -488,18 +488,28 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
488488
typeConfiguration
489489
);
490490

491-
if ( getVersion().isSameOrAfter(2, 0, 20) ) {
492-
// Introduced in 2.0 SPS 02
491+
if ( getVersion().isSameOrAfter( 2, 0 ) ) {
492+
// Introduced in 2.0 SPS 00
493493
functionFactory.jsonValue_no_passing();
494494
functionFactory.jsonQuery_no_passing();
495495
functionFactory.jsonExists_hana();
496-
if ( getVersion().isSameOrAfter(2, 0, 40) ) {
497-
// Introduced in 2.0 SPS 04
498-
functionFactory.jsonObject_hana();
499-
functionFactory.jsonArray_hana();
500-
functionFactory.jsonArrayAgg_hana();
501-
functionFactory.jsonObjectAgg_hana();
496+
497+
functionFactory.unnest_hana();
498+
// functionFactory.json_table();
499+
500+
if ( getVersion().isSameOrAfter(2, 0, 20 ) ) {
501+
if ( getVersion().isSameOrAfter( 2, 0, 40 ) ) {
502+
// Introduced in 2.0 SPS 04
503+
functionFactory.jsonObject_hana();
504+
functionFactory.jsonArray_hana();
505+
functionFactory.jsonArrayAgg_hana();
506+
functionFactory.jsonObjectAgg_hana();
507+
}
508+
509+
// functionFactory.xmltable();
502510
}
511+
512+
// functionFactory.xmlextract();
503513
}
504514
}
505515

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 ) ) {

0 commit comments

Comments
 (0)