From e7f5f886c707d1cddb8cb03d7f083fdbdeb96279 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 | 34 ++++++++++------ .../array/OracleArrayIntersectsFunction.java | 33 +++++++++------ 4 files changed, 77 insertions(+), 40 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 329fc32e96..80d28ff41f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java @@ -40,6 +40,7 @@ import org.hibernate.sql.ast.tree.from.ValuesTableReference; 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; @@ -121,6 +122,15 @@ public class OracleSqlAstTranslator extends SqlAstTrans 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 1f2653b442..e8ef525c3b 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 @@ -32,27 +32,35 @@ public class OracleArrayContainsFunction extends AbstractArrayContainsFunction { 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 aa66dd8882..dc658a66dd 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 @@ -26,17 +26,27 @@ public class OracleArrayIncludesFunction extends AbstractArrayIncludesFunction { 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 c3e5ef7730..11a835e328 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 @@ -26,18 +26,27 @@ public class OracleArrayIntersectsFunction extends AbstractArrayIntersectsFuncti 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)))" ); + } } }