diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java index 0cea4cac6d4c..2de663be1b30 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java @@ -57,11 +57,13 @@ import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; +import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers; import org.hibernate.query.sqm.sql.SqmTranslator; import org.hibernate.query.sqm.sql.SqmTranslatorFactory; import org.hibernate.query.sqm.sql.StandardSqmTranslatorFactory; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.service.ServiceRegistry; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.SqlAppender; @@ -74,7 +76,10 @@ import org.hibernate.tool.schema.internal.StandardForeignKeyExporter; import org.hibernate.tool.schema.internal.StandardTableExporter; import org.hibernate.tool.schema.spi.Exporter; +import org.hibernate.type.JavaObjectType; +import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.jdbc.ClobJdbcType; +import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.sql.DdlType; import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType; @@ -85,6 +90,7 @@ import jakarta.persistence.TemporalType; import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; +import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING; import static org.hibernate.type.SqlTypes.BIGINT; import static org.hibernate.type.SqlTypes.BINARY; import static org.hibernate.type.SqlTypes.FLOAT; @@ -303,10 +309,10 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio super.initializeFunctionRegistry(functionContributions); CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions); + functionFactory.aggregates( this, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); functionFactory.instr(); functionFactory.substr(); - functionFactory.substring_substr(); - //also natively supports ANSI-style substring() + functionFactory.substringFromFor(); functionFactory.trunc(); functionFactory.trim2(); functionFactory.space(); @@ -329,12 +335,30 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio functionFactory.monthsBetween(); functionFactory.stddev(); functionFactory.variance(); - functionFactory.locate_positionSubstring(); + functionFactory.bitLength_pattern( "length(?1)*8" ); + + if ( getVersion().isSameOrAfter( 12 ) ) { + functionFactory.locate_charindex(); + } //coalesce() and nullif() both supported since Informix 12 functionContributions.getFunctionRegistry().register( "least", new CaseLeastGreatestEmulation( true ) ); functionContributions.getFunctionRegistry().register( "greatest", new CaseLeastGreatestEmulation( false ) ); + functionContributions.getFunctionRegistry().namedDescriptorBuilder( "matches" ) + .setInvariantType( functionContributions.getTypeConfiguration() + .getBasicTypeRegistry() + .resolve( StandardBasicTypes.STRING ) + ) + .setExactArgumentCount( 2 ) + .setArgumentTypeResolver( + StandardFunctionArgumentTypeResolvers.impliedOrInvariant( + functionContributions.getTypeConfiguration(), + STRING + ) + ) + .setArgumentListSignature( "(STRING string, STRING pattern)" ) + .register(); if ( supportsWindowFunctions() ) { functionFactory.windowFunctions(); } @@ -704,6 +728,11 @@ public String currentDate() { return "today"; } + @Override + public String currentTime() { + return currentTimestamp(); + } + @Override public String currentTimestamp() { return "current"; @@ -853,6 +882,17 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration().getJdbcTypeRegistry(); jdbcTypeRegistry.addDescriptor( Types.NCLOB, ClobJdbcType.DEFAULT ); typeContributions.contributeJdbcType( VarcharUUIDJdbcType.INSTANCE ); + typeContributions.contributeJdbcType( ObjectNullAsBinaryTypeJdbcType.INSTANCE ); + + // Until we remove StandardBasicTypes, we have to keep this + typeContributions.contributeType( + new JavaObjectType( + ObjectNullAsBinaryTypeJdbcType.INSTANCE, + typeContributions.getTypeConfiguration() + .getJavaTypeRegistry() + .getDescriptor( Object.class ) + ) + ); } @Override diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixFunctionTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixFunctionTest.java index 29ab032044b4..ec1c686aa55f 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixFunctionTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixFunctionTest.java @@ -179,6 +179,23 @@ public void testCurrentTimestamp(SessionFactoryScope scope) { ); } + @Test + @JiraKey( value = "HHH-18369" ) + public void testMatches(SessionFactoryScope scope) { + scope.inTransaction( + (session) -> { + String country = (String) session.createQuery( + "select e.country " + + "from Event e " + + "where e.id = :id and matches(e.country, :country) = 'T'" ) + .setParameter( "id", event.id ) + .setParameter( "country", "R*" ) + .getSingleResult(); + assertEquals( "Romania", country ); + } + ); + } + private Calendar todayCalendar() { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 0); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java index 1b0af23e1b68..468f82fe2d46 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java @@ -11,6 +11,7 @@ import org.hibernate.ScrollableResults; import org.hibernate.TypeMismatchException; import org.hibernate.cfg.Environment; +import org.hibernate.community.dialect.InformixDialect; import org.hibernate.community.dialect.DerbyDialect; import org.hibernate.dialect.CockroachDialect; import org.hibernate.dialect.DB2Dialect; @@ -746,6 +747,7 @@ public void testSelectClauseCaseWithSum(SessionFactoryScope scope) { @Test @JiraKey(value = "HHH-4150") + @SkipForDialect( dialectClass = InformixDialect.class, majorVersion = 11, minorVersion = 70, reason = "Informix does not support case with count distinct") public void testSelectClauseCaseWithCountDistinct(SessionFactoryScope scope) { scope.inTransaction( session -> { @@ -3642,17 +3644,21 @@ public void testEJBQLFunctions(SessionFactoryScope scope) { hql = "select length(a.description) from Animal a"; session.createQuery( hql ).list(); - //note: postgres and db2 don't have a 3-arg form, it gets transformed to 2-args - hql = "from Animal a where locate('abc', a.description, 2) = 2"; - session.createQuery( hql ).list(); + Dialect dialect = session.getDialect(); + // Informix before version 12 didn't support finding the index of substrings + if ( !(dialect instanceof InformixDialect && dialect.getVersion().isBefore( 12 )) ) { + //note: postgres and db2 don't have a 3-arg form, it gets transformed to 2-args + hql = "from Animal a where locate('abc', a.description, 2) = 2"; + session.createQuery( hql ).list(); - hql = "from Animal a where locate('abc', a.description) = 2"; - session.createQuery( hql ).list(); + hql = "from Animal a where locate('abc', a.description) = 2"; + session.createQuery( hql ).list(); - hql = "select locate('cat', a.description, 2) from Animal a"; - session.createQuery( hql ).list(); + hql = "select locate('cat', a.description, 2) from Animal a"; + session.createQuery( hql ).list(); + } - if ( !(session.getDialect() instanceof DB2Dialect) ) { + if ( !(dialect instanceof DB2Dialect) ) { hql = "from Animal a where trim(trailing '_' from a.description) = 'cat'"; session.createQuery( hql ).list(); @@ -3666,7 +3672,7 @@ public void testEJBQLFunctions(SessionFactoryScope scope) { session.createQuery( hql ).list(); } - if ( !(session.getDialect() instanceof HSQLDialect) ) { //HSQL doesn't like trim() without specification + if ( !(dialect instanceof HSQLDialect) ) { //HSQL doesn't like trim() without specification hql = "from Animal a where trim(a.description) = 'cat'"; session.createQuery( hql ).list(); } @@ -3725,6 +3731,7 @@ public void testOrderByExtraParenthesis(SessionFactoryScope scope) throws Except } } + @Test @RequiresDialectFeature( feature = DialectFeatureChecks.SupportSubqueryAsLeftHandSideInPredicate.class, comment = "Database does not support using subquery as singular value expression"