From 91627440a3514e2051f2c0941693fd7dbbae5382 Mon Sep 17 00:00:00 2001 From: Philippe Marschall Date: Sun, 8 Sep 2024 17:41:36 +0200 Subject: [PATCH] HHH-18587 Implement Oracle array functions using set operations https://hibernate.atlassian.net/browse/HHH-18587 --- .../dialect/OracleSqlAstTranslator.java | 10 +++++ .../array/OracleArrayContainsFunction.java | 40 +++++++++++-------- .../array/OracleArrayIncludesFunction.java | 37 ++++++++++------- .../array/OracleArrayIntersectsFunction.java | 33 +++++++++------ 4 files changed, 77 insertions(+), 43 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java index 00558358553b..866fff6534b5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java @@ -42,6 +42,7 @@ import org.hibernate.sql.ast.tree.insert.ConflictClause; import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; import org.hibernate.sql.ast.tree.insert.Values; +import org.hibernate.sql.ast.tree.predicate.InArrayPredicate; import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.select.QueryGroup; @@ -123,6 +124,15 @@ protected boolean needsRecursiveKeywordInWithClause() { return false; } + @Override + public void visitInArrayPredicate(InArrayPredicate inArrayPredicate) { + // column in (select column_value from(?) ) + inArrayPredicate.getTestExpression().accept( this ); + appendSql( " in (select column_value from table(" ); + inArrayPredicate.getArrayParameter().accept( this ); + appendSql( "))" ); + } + @Override protected boolean supportsWithClauseInSubquery() { // Oracle has some limitations, see ORA-32034, so we just report false here for simplicity diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsFunction.java index 73b49f80568b..b5a5946fd4dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsFunction.java @@ -34,27 +34,35 @@ public void render( final Expression needleExpression = (Expression) sqlAstArguments.get( 1 ); final JdbcMappingContainer needleTypeContainer = needleExpression.getExpressionType(); final JdbcMapping needleType = needleTypeContainer == null ? null : needleTypeContainer.getSingleJdbcMapping(); - final String arrayTypeName = DdlTypeHelper.getTypeName( - haystackExpression.getExpressionType(), - walker.getSessionFactory().getTypeConfiguration() - ); - sqlAppender.appendSql( arrayTypeName ); if ( needleType == null || needleType instanceof BasicPluralType ) { LOG.deprecatedArrayContainsWithArray(); - sqlAppender.append( "_includes(" ); - haystackExpression.accept( walker ); - sqlAppender.append( ',' ); - sqlAstArguments.get( 1 ).accept( walker ); - sqlAppender.append( ',' ); - sqlAppender.append( nullable ? "1" : "0" ); - sqlAppender.append( ")>0" ); + if ( nullable ) { + final String arrayTypeName = DdlTypeHelper.getTypeName( + haystackExpression.getExpressionType(), + walker.getSessionFactory().getTypeConfiguration() + ); + sqlAppender.appendSql( arrayTypeName ); + sqlAppender.append( "_includes(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ',' ); + sqlAstArguments.get( 1 ).accept( walker ); + sqlAppender.append( ',' ); + sqlAppender.append( "1" ); + sqlAppender.append( ")>0" ); + } + else { + sqlAppender.append( " exists (select 1 from (table (" ); + needleExpression.accept( walker ); + sqlAppender.append( ") join (table (" ); + haystackExpression.accept( walker ); + sqlAppender.append( ")) using (column_value)))" ); + } } else { - sqlAppender.append( "_position(" ); - haystackExpression.accept( walker ); - sqlAppender.append( ',' ); needleExpression.accept( walker ); - sqlAppender.append( ")>0" ); + sqlAppender.append( " in (select column_value from table(" ); + haystackExpression.accept( walker ); + sqlAppender.append( "))" ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIncludesFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIncludesFunction.java index 818f61cc1825..60417d11cbdf 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIncludesFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIncludesFunction.java @@ -8,14 +8,11 @@ import java.util.List; -import org.hibernate.metamodel.mapping.JdbcMapping; -import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.type.BasicPluralType; import org.hibernate.type.spi.TypeConfiguration; public class OracleArrayIncludesFunction extends AbstractArrayIncludesFunction { @@ -31,17 +28,27 @@ public void render( ReturnableType returnType, SqlAstTranslator walker) { final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); - final String arrayTypeName = DdlTypeHelper.getTypeName( - haystackExpression.getExpressionType(), - walker.getSessionFactory().getTypeConfiguration() - ); - sqlAppender.appendSql( arrayTypeName ); - sqlAppender.append( "_includes(" ); - haystackExpression.accept( walker ); - sqlAppender.append( ',' ); - sqlAstArguments.get( 1 ).accept( walker ); - sqlAppender.append( ',' ); - sqlAppender.append( nullable ? "1" : "0" ); - sqlAppender.append( ")>0" ); + if ( nullable ) { + final String arrayTypeName = DdlTypeHelper.getTypeName( + haystackExpression.getExpressionType(), + walker.getSessionFactory().getTypeConfiguration() + ); + sqlAppender.appendSql( arrayTypeName ); + sqlAppender.append( "_includes(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ',' ); + sqlAstArguments.get( 1 ).accept( walker ); + sqlAppender.append( ',' ); + sqlAppender.append( "1" ); + sqlAppender.append( ")>0" ); + } + else { + sqlAppender.append( " not exists ((select column_value from table (" ); + sqlAstArguments.get( 1 ).accept( walker ); + sqlAppender.append( ")) minus (select column_value from table(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ")))" ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIntersectsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIntersectsFunction.java index 95fdad4de81c..15dca95e00ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIntersectsFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayIntersectsFunction.java @@ -28,18 +28,27 @@ public void render( ReturnableType returnType, SqlAstTranslator walker) { final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); - final String arrayTypeName = DdlTypeHelper.getTypeName( - haystackExpression.getExpressionType(), - walker.getSessionFactory().getTypeConfiguration() - ); - sqlAppender.appendSql( arrayTypeName ); - sqlAppender.append( "_intersects(" ); - haystackExpression.accept( walker ); - sqlAppender.append( ',' ); - sqlAstArguments.get( 1 ).accept( walker ); - sqlAppender.append( ',' ); - sqlAppender.append( nullable ? "1" : "0" ); - sqlAppender.append( ")>0" ); + if ( nullable ) { + final String arrayTypeName = DdlTypeHelper.getTypeName( + haystackExpression.getExpressionType(), + walker.getSessionFactory().getTypeConfiguration() + ); + sqlAppender.appendSql( arrayTypeName ); + sqlAppender.append( "_intersects(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ',' ); + sqlAstArguments.get( 1 ).accept( walker ); + sqlAppender.append( ',' ); + sqlAppender.append( "1" ); + sqlAppender.append( ")>0" ); + } + else { + sqlAppender.append( " exists (select 1 from (table (" ); + sqlAstArguments.get( 1 ).accept( walker ); + sqlAppender.append( ") join (table (" ); + haystackExpression.accept( walker ); + sqlAppender.append( ")) using (column_value)))" ); + } } }