From 2baa66df532b963dd24682777695350a61d53d57 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 29 Jul 2025 10:48:04 +0200 Subject: [PATCH 1/2] Fix Envers issues with wrong CockroachDB LOB JdbcTypes --- .../community/dialect/CockroachLegacyDialect.java | 11 ++++++----- .../java/org/hibernate/dialect/CockroachDialect.java | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java index c0b8b5840304..13a9cbae4eb8 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java @@ -61,10 +61,11 @@ import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; import org.hibernate.type.JavaObjectType; +import org.hibernate.type.descriptor.jdbc.BlobJdbcType; +import org.hibernate.type.descriptor.jdbc.ClobJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.jdbc.NClobJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType; -import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType; -import org.hibernate.type.descriptor.jdbc.VarcharJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl; import org.hibernate.type.descriptor.sql.internal.NamedNativeEnumDdlTypeImpl; @@ -391,9 +392,9 @@ protected void contributeCockroachTypes(TypeContributions typeContributions, Ser } // Force Blob binding to byte[] for CockroachDB - jdbcTypeRegistry.addDescriptor( Types.BLOB, VarbinaryJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptor( Types.CLOB, VarcharJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptor( Types.NCLOB, VarcharJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptor( Types.BLOB, BlobJdbcType.MATERIALIZED ); + jdbcTypeRegistry.addDescriptor( Types.CLOB, ClobJdbcType.MATERIALIZED ); + jdbcTypeRegistry.addDescriptor( Types.NCLOB, NClobJdbcType.MATERIALIZED ); // The next two contributions are the same as for Postgresql typeContributions.contributeJdbcType( ObjectNullAsBinaryTypeJdbcType.INSTANCE ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java index c9d3c00c5550..ec2ee505559e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java @@ -61,11 +61,12 @@ import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; import org.hibernate.type.JavaObjectType; +import org.hibernate.type.descriptor.jdbc.BlobJdbcType; +import org.hibernate.type.descriptor.jdbc.ClobJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.jdbc.NClobJdbcType; import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType; import org.hibernate.type.descriptor.jdbc.UUIDJdbcType; -import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType; -import org.hibernate.type.descriptor.jdbc.VarcharJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl; import org.hibernate.type.descriptor.sql.internal.NamedNativeEnumDdlTypeImpl; @@ -394,9 +395,9 @@ protected void contributeCockroachTypes(TypeContributions typeContributions, Ser } // Force Blob binding to byte[] for CockroachDB - jdbcTypeRegistry.addDescriptor( Types.BLOB, VarbinaryJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptor( Types.CLOB, VarcharJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptor( Types.NCLOB, VarcharJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptor( Types.BLOB, BlobJdbcType.MATERIALIZED ); + jdbcTypeRegistry.addDescriptor( Types.CLOB, ClobJdbcType.MATERIALIZED ); + jdbcTypeRegistry.addDescriptor( Types.NCLOB, NClobJdbcType.MATERIALIZED ); // The next two contributions are the same as for Postgresql typeContributions.contributeJdbcType( ObjectNullAsBinaryTypeJdbcType.INSTANCE ); From 09f82e3a21d7bc754fc591f5a453fc07869bbc59 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 29 Jul 2025 12:45:41 +0200 Subject: [PATCH 2/2] HHH-18956 Fix native query brace replacement dollar quoted literal support --- .../query/sql/internal/SQLQueryParser.java | 11 ++- .../PostgisDollarQuoteNativeQueryTest.java | 92 +++++++++++++++++++ 2 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisDollarQuoteNativeQueryTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/SQLQueryParser.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/SQLQueryParser.java index 94420df0893f..045d24df06ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/SQLQueryParser.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/SQLQueryParser.java @@ -92,10 +92,15 @@ protected String substituteBrackets(String sqlQuery) throws QueryException { } break; case '"': - if (!singleQuoted && !escaped) { - doubleQuoted = !doubleQuoted; + if (escaped) { + token.append(ch); + } + else { + if ( !singleQuoted ) { + doubleQuoted = !doubleQuoted; + } + result.append( ch ); } - result.append(ch); break; case '{': if (!singleQuoted && !doubleQuoted) { diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisDollarQuoteNativeQueryTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisDollarQuoteNativeQueryTest.java new file mode 100644 index 000000000000..e6b0e6af5c9a --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisDollarQuoteNativeQueryTest.java @@ -0,0 +1,92 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.spatial.dialect.postgis; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import org.geolatte.geom.G2D; +import org.geolatte.geom.Point; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.Jira; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.type.SqlTypes; +import org.junit.jupiter.api.Test; + + +import static org.geolatte.geom.builder.DSL.g; +import static org.geolatte.geom.builder.DSL.point; +import static org.geolatte.geom.crs.CoordinateReferenceSystems.WGS84; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@DomainModel(annotatedClasses = PostgisDollarQuoteNativeQueryTest.Location.class ) +@SessionFactory +@RequiresDialect(PostgreSQLDialect.class) +@Jira( "https://hibernate.atlassian.net/browse/HHH-18956" ) +class PostgisDollarQuoteNativeQueryTest { + + private static final Long LOCATION_ID = 123412L; + private static final String DOLLAR_QUOTE = "$asdas$"; + + @Test + void test(SessionFactoryScope scope) { + scope.inTransaction( s -> { + final Point point = point( WGS84, g( 30.5, 50.4 ) ); + //noinspection SqlSourceToSinkFlow + s.createNativeMutationQuery( + String.format( + "INSERT INTO location (id, point) " + + "VALUES (%s, %s) " + + "ON CONFLICT DO NOTHING;", + DOLLAR_QUOTE + LOCATION_ID + DOLLAR_QUOTE, + String.format( + "ST_SetSRID(ST_GeomFromGeoJSON(%s%s%s), 4326)", + DOLLAR_QUOTE, + toJsonString( point ), + DOLLAR_QUOTE + ) + ) + ).executeUpdate(); + + final Location location = s.find( Location.class, LOCATION_ID ); + assertEquals( point, location.point ); + } ); + } + + private static String toJsonString(Point point) { + return "{\"type\":\"" + point.getGeometryType().getCamelCased() + "\",\"coordinates\":" + point.getPosition() + "}"; + } + + @Entity(name = "Location") + public static class Location { + + @Id + Long id; + + @JdbcTypeCode(SqlTypes.GEOMETRY) + Point point; + + public Location() { + } + + public Location(Long id, Point point) { + this.id = id; + this.point = point; + } + + @Override + public String toString() { + return "Location{" + + "id=" + id + + ", point=" + point + + '}'; + } + } +}