diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index fcc4f258bf3b..46d3b56a67a2 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -12,6 +12,7 @@
+
diff --git a/docker_db.sh b/docker_db.sh
index f6fcce3a3c29..85538cd6a07a 100755
--- a/docker_db.sh
+++ b/docker_db.sh
@@ -659,8 +659,6 @@ disable_userland_proxy() {
sudo service docker stop
echo "Updating /etc/docker/daemon.json..."
sudo bash -c "export docker_daemon_json='$docker_daemon_json'; echo \"\${docker_daemon_json/\}/,}\\\"userland-proxy\\\": false}\" > /etc/docker/daemon.json"
- echo "New docker daemon config:"
- cat /etc/docker/daemon.json
echo "Starting docker..."
sudo service docker start
echo "Service status:"
diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java
index e28b49c3f3bd..f0ca40a7bacb 100644
--- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java
+++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java
@@ -63,7 +63,9 @@
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
+import org.hibernate.mapping.AggregateColumn;
import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.DB2CallableStatementSupport;
@@ -87,6 +89,8 @@
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorDB2DatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
+import org.hibernate.tool.schema.internal.StandardTableExporter;
+import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
@@ -96,6 +100,7 @@
import org.hibernate.type.descriptor.jdbc.CharJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.InstantJdbcType;
+import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.LocalDateJdbcType;
import org.hibernate.type.descriptor.jdbc.LocalDateTimeJdbcType;
import org.hibernate.type.descriptor.jdbc.LocalTimeJdbcType;
@@ -154,6 +159,17 @@ public class DB2LegacyDialect extends Dialect {
? LegacyDB2LimitHandler.INSTANCE
: DB2LimitHandler.INSTANCE;
private final UniqueDelegate uniqueDelegate = createUniqueDelegate();
+ private final StandardTableExporter db2TableExporter = new StandardTableExporter( this ) {
+ @Override
+ protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
+ final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
+ if ( jdbcType.isLob() || jdbcType.isXml() ) {
+ // LOB or XML columns can't have check constraints
+ return;
+ }
+ super.applyAggregateColumnCheck( buf, aggregateColumn );
+ }
+ };
public DB2LegacyDialect() {
this( DatabaseVersion.make( 9, 0 ) );
@@ -189,6 +205,11 @@ public DatabaseVersion getDB2Version() {
return this.getVersion();
}
+ @Override
+ public Exporter
getTableExporter() {
+ return this.db2TableExporter;
+ }
+
@Override
public int getDefaultStatementBatchSize() {
return 0;
diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java
index 7446bf067426..67be120e37a1 100644
--- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java
+++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java
@@ -53,7 +53,9 @@
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.internal.util.StringHelper;
+import org.hibernate.mapping.AggregateColumn;
import org.hibernate.mapping.CheckConstraint;
+import org.hibernate.mapping.Table;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
@@ -81,6 +83,7 @@
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
+import org.hibernate.tool.schema.internal.StandardTableExporter;
import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.NullType;
@@ -172,6 +175,17 @@ public class OracleLegacyDialect extends Dialect {
private final OracleUserDefinedTypeExporter userDefinedTypeExporter = new OracleUserDefinedTypeExporter( this );
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
private final SequenceSupport oracleSequenceSupport = OracleSequenceSupport.getInstance(this);
+ private final StandardTableExporter oracleTableExporter = new StandardTableExporter( this ) {
+ @Override
+ protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
+ final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
+ if ( dialect.getVersion().isBefore( 23, 6 ) && jdbcType.isXml() ) {
+ // ORA-00600 when selecting XML columns that have a check constraint was fixed in 23.6
+ return;
+ }
+ super.applyAggregateColumnCheck( buf, aggregateColumn );
+ }
+ };
public OracleLegacyDialect() {
this( DatabaseVersion.make( 8, 0 ) );
@@ -503,6 +517,8 @@ public String castPattern(CastType from, CastType to) {
return "to_timestamp_tz(?1,'YYYY-MM-DD HH24:MI:SS.FF9 TZR')";
}
break;
+ case XML:
+ return "xmlparse(document ?1)";
}
return super.castPattern(from, to);
}
@@ -1042,6 +1058,11 @@ public SequenceSupport getSequenceSupport() {
return oracleSequenceSupport;
}
+ @Override
+ public Exporter getTableExporter() {
+ return oracleTableExporter;
+ }
+
@Override
public String getQuerySequencesString() {
return "select * from all_sequences";
diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java
index 73f12a335763..e906643aa946 100644
--- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java
+++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java
@@ -53,6 +53,8 @@
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
+import org.hibernate.mapping.AggregateColumn;
+import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.PostgreSQLCallableStatementSupport;
@@ -76,6 +78,8 @@
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
+import org.hibernate.tool.schema.internal.StandardTableExporter;
+import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
@@ -143,6 +147,17 @@ public class PostgreSQLLegacyDialect extends Dialect {
protected final PostgreSQLDriverKind driverKind;
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
+ private final StandardTableExporter postgresqlTableExporter = new StandardTableExporter( this ) {
+ @Override
+ protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
+ final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
+ if ( jdbcType.isXml() ) {
+ // Requires the use of xmltable which is not supported in check constraints
+ return;
+ }
+ super.applyAggregateColumnCheck( buf, aggregateColumn );
+ }
+ };
public PostgreSQLLegacyDialect() {
this( DatabaseVersion.make( 8, 0 ) );
@@ -1536,6 +1551,11 @@ public UniqueDelegate getUniqueDelegate() {
return uniqueDelegate;
}
+ @Override
+ public Exporter getTableExporter() {
+ return postgresqlTableExporter;
+ }
+
/**
* @return {@code true}, but only because we can "batch" truncate
*/
diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java
index 978cc6a747fe..73911217fbd5 100644
--- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java
+++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java
@@ -52,8 +52,10 @@
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.internal.util.StringHelper;
+import org.hibernate.mapping.AggregateColumn;
import org.hibernate.mapping.CheckConstraint;
import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
import org.hibernate.query.sqm.CastType;
import org.hibernate.query.common.FetchClauseType;
import org.hibernate.query.sqm.IntervalType;
@@ -68,6 +70,7 @@
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.internal.StandardSequenceExporter;
+import org.hibernate.tool.schema.internal.StandardTableExporter;
import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
@@ -142,6 +145,17 @@ public Size resolveSize(
}
}
};
+ private final StandardTableExporter sqlServerTableExporter = new StandardTableExporter( this ) {
+ @Override
+ protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
+ final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
+ if ( jdbcType.isXml() ) {
+ // XML columns can't have check constraints
+ return;
+ }
+ super.applyAggregateColumnCheck( buf, aggregateColumn );
+ }
+ };
public SQLServerLegacyDialect() {
@@ -1165,6 +1179,11 @@ public UniqueDelegate getUniqueDelegate() {
return uniqueDelegate;
}
+ @Override
+ public Exporter getTableExporter() {
+ return this.sqlServerTableExporter;
+ }
+
@Override
public Exporter getSequenceExporter() {
if ( exporter == null ) {
diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java
index 1f91eca53127..a16fbc6d87de 100644
--- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java
+++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java
@@ -17,6 +17,8 @@
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.SybaseDriverKind;
+import org.hibernate.dialect.aggregate.AggregateSupport;
+import org.hibernate.dialect.aggregate.SybaseASEAggregateSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.TopLimitHandler;
@@ -228,6 +230,11 @@ protected SqlAstTranslator buildTranslator(
};
}
+ @Override
+ public AggregateSupport getAggregateSupport() {
+ return SybaseASEAggregateSupport.valueOf( this );
+ }
+
/**
* The Sybase ASE {@code BIT} type does not allow
* null values, so we don't use it.
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java
index 7c0ee8793f8f..aad3ef4fedf6 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java
@@ -93,6 +93,7 @@
import static org.hibernate.cfg.AvailableSettings.JPA_COMPLIANCE;
import static org.hibernate.cfg.AvailableSettings.WRAPPER_ARRAY_HANDLING;
+import static org.hibernate.cfg.MappingSettings.XML_FORMAT_MAPPER_LEGACY_FORMAT;
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
import static org.hibernate.internal.util.StringHelper.nullIfEmpty;
@@ -652,6 +653,7 @@ public static class MetadataBuildingOptionsImpl
private final String schemaCharset;
private final boolean xmlMappingEnabled;
private final boolean allowExtensionsInCdi;
+ private final boolean xmlFormatMapperLegacyFormat;
public MetadataBuildingOptionsImpl(StandardServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
@@ -670,6 +672,7 @@ public MetadataBuildingOptionsImpl(StandardServiceRegistry serviceRegistry) {
BOOLEAN,
true
);
+ xmlFormatMapperLegacyFormat = configService.getSetting( XML_FORMAT_MAPPER_LEGACY_FORMAT, BOOLEAN, false );
implicitDiscriminatorsForJoinedInheritanceSupported = configService.getSetting(
AvailableSettings.IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS,
@@ -954,6 +957,11 @@ public boolean isAllowExtensionsInCdi() {
return allowExtensionsInCdi;
}
+ @Override
+ public boolean isXmlFormatMapperLegacyFormatEnabled() {
+ return xmlFormatMapperLegacyFormat;
+ }
+
/**
* Yuck. This is needed because JPA lets users define "global building options"
* in {@code orm.xml} mappings. Forget that there are generally multiple
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java
index 17a7c976b955..281a9fe2277a 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java
@@ -169,6 +169,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
private Object validatorFactoryReference;
private FormatMapper jsonFormatMapper;
private FormatMapper xmlFormatMapper;
+ private final boolean xmlFormatMapperLegacyFormatEnabled;
// SessionFactory behavior
private final boolean jpaBootstrap;
@@ -326,7 +327,8 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo
);
this.xmlFormatMapper = determineXmlFormatMapper(
configurationSettings.get( AvailableSettings.XML_FORMAT_MAPPER ),
- strategySelector
+ strategySelector,
+ this.xmlFormatMapperLegacyFormatEnabled = context.getMetadataBuildingOptions().isXmlFormatMapperLegacyFormatEnabled()
);
this.sessionFactoryName = (String) configurationSettings.get( SESSION_FACTORY_NAME );
@@ -892,13 +894,13 @@ private static FormatMapper determineJsonFormatMapper(Object setting, StrategySe
);
}
- private static FormatMapper determineXmlFormatMapper(Object setting, StrategySelector strategySelector) {
+ private static FormatMapper determineXmlFormatMapper(Object setting, StrategySelector strategySelector, boolean legacyFormat) {
return strategySelector.resolveDefaultableStrategy(
FormatMapper.class,
setting,
(Callable) () -> {
- final FormatMapper jacksonFormatMapper = getXMLJacksonFormatMapperOrNull();
- return jacksonFormatMapper != null ? jacksonFormatMapper : new JaxbXmlFormatMapper();
+ final FormatMapper jacksonFormatMapper = getXMLJacksonFormatMapperOrNull( legacyFormat );
+ return jacksonFormatMapper != null ? jacksonFormatMapper : new JaxbXmlFormatMapper( legacyFormat );
}
);
}
@@ -1358,6 +1360,11 @@ public FormatMapper getXmlFormatMapper() {
return xmlFormatMapper;
}
+ @Override
+ public boolean isXmlFormatMapperLegacyFormatEnabled() {
+ return xmlFormatMapperLegacyFormatEnabled;
+ }
+
@Override
public boolean isPassProcedureParameterNames() {
return passProcedureParameterNames;
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java
index 2db486b4c15d..83174af07d78 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java
@@ -182,4 +182,9 @@ public boolean isXmlMappingEnabled() {
public boolean isAllowExtensionsInCdi() {
return delegate.isAllowExtensionsInCdi();
}
+
+ @Override
+ public boolean isXmlFormatMapperLegacyFormatEnabled() {
+ return delegate.isXmlFormatMapperLegacyFormatEnabled();
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java
index 85461af84dc7..15e912a7698e 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java
@@ -523,6 +523,11 @@ public FormatMapper getXmlFormatMapper() {
return delegate.getXmlFormatMapper();
}
+ @Override
+ public boolean isXmlFormatMapperLegacyFormatEnabled() {
+ return delegate.isXmlFormatMapperLegacyFormatEnabled();
+ }
+
@Override
public boolean isPassProcedureParameterNames() {
return delegate.isPassProcedureParameterNames();
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java
index 560f08854b1d..17780981b433 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java
@@ -6,6 +6,7 @@
import java.util.List;
+import org.hibernate.Incubating;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
@@ -144,6 +145,15 @@ default CollectionSemanticsResolver getPersistentCollectionRepresentationResolve
*/
boolean isMultiTenancyEnabled();
+ /**
+ * Whether to use the legacy format for serializing/deserializing XML data.
+ *
+ * @since 7.0
+ * @see org.hibernate.cfg.MappingSettings#XML_FORMAT_MAPPER_LEGACY_FORMAT
+ */
+ @Incubating
+ boolean isXmlFormatMapperLegacyFormatEnabled();
+
/**
* @return the {@link TypeConfiguration} belonging to the {@link BootstrapContext}
*/
diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java
index 949f7bd2ce47..39a5c463c9c3 100644
--- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java
+++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java
@@ -571,6 +571,15 @@ default boolean isCollectionsInDefaultFetchGroupEnabled() {
@Incubating
FormatMapper getXmlFormatMapper();
+ /**
+ * Whether to use the legacy format for serializing/deserializing XML data.
+ *
+ * @since 7.0
+ * @see org.hibernate.cfg.MappingSettings#XML_FORMAT_MAPPER_LEGACY_FORMAT
+ */
+ @Incubating
+ boolean isXmlFormatMapperLegacyFormatEnabled();
+
/**
* The default tenant identifier java type to use, in case no explicit tenant identifier property is defined.
*
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/MappingSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/MappingSettings.java
index fd9c78b74117..cc2701d46c83 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/MappingSettings.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/MappingSettings.java
@@ -325,6 +325,17 @@ public interface MappingSettings {
@Incubating
String XML_FORMAT_MAPPER = "hibernate.type.xml_format_mapper";
+ /**
+ * Specifies whether to use the legacy provider specific and non-portable XML format for collections and byte arrays
+ * for XML serialization/deserialization.
+ *
+ * {@code false} by default. This property only exists for backwards compatibility.
+ *
+ * @since 7.0
+ */
+ @Incubating
+ String XML_FORMAT_MAPPER_LEGACY_FORMAT = "hibernate.type.xml_format_mapper.legacy_format";
+
/**
* Configurable control over how to handle {@code Byte[]} and {@code Character[]} types
* encountered in the application domain model. Allowable semantics are defined by
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java
index c6b2dfde742f..d4541f5f829c 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java
@@ -53,7 +53,9 @@
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
+import org.hibernate.mapping.AggregateColumn;
import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.procedure.internal.DB2CallableStatementSupport;
@@ -77,6 +79,8 @@
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorDB2DatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
+import org.hibernate.tool.schema.internal.StandardTableExporter;
+import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
@@ -84,6 +88,7 @@
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.InstantJdbcType;
+import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.LocalDateJdbcType;
import org.hibernate.type.descriptor.jdbc.LocalDateTimeJdbcType;
import org.hibernate.type.descriptor.jdbc.LocalTimeJdbcType;
@@ -146,6 +151,17 @@ public class DB2Dialect extends Dialect {
? LegacyDB2LimitHandler.INSTANCE
: DB2LimitHandler.INSTANCE;
private final UniqueDelegate uniqueDelegate = createUniqueDelegate();
+ private final StandardTableExporter db2TableExporter = new StandardTableExporter( this ) {
+ @Override
+ protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
+ final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
+ if ( jdbcType.isLob() || jdbcType.isXml() ) {
+ // LOB or XML columns can't have check constraints
+ return;
+ }
+ super.applyAggregateColumnCheck( buf, aggregateColumn );
+ }
+ };
public DB2Dialect() {
this( MINIMUM_VERSION );
@@ -171,6 +187,11 @@ public DatabaseVersion getDB2Version() {
return this.getVersion();
}
+ @Override
+ public Exporter
getTableExporter() {
+ return this.db2TableExporter;
+ }
+
@Override
public int getDefaultStatementBatchSize() {
return 0;
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2JsonJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2JsonJdbcType.java
index b40b88efbef8..0ed3854cbad5 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/H2JsonJdbcType.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2JsonJdbcType.java
@@ -11,6 +11,7 @@
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
+import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
@@ -31,6 +32,11 @@ protected H2JsonJdbcType(EmbeddableMappingType embeddableMappingType) {
super( embeddableMappingType );
}
+ @Override
+ public int getJdbcTypeCode() {
+ return SqlTypes.VARBINARY;
+ }
+
@Override
public String toString() {
return "H2JsonJdbcType";
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/JsonHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/JsonHelper.java
index 6fc4b21a4cd3..42c87f77cf73 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/JsonHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/JsonHelper.java
@@ -111,7 +111,6 @@ private static void toString(
Object domainValue,
char separator) {
final Object[] values = embeddableMappingType.getValues( domainValue );
- final int numberOfAttributes = embeddableMappingType.getNumberOfAttributeMappings();
for ( int i = 0; i < values.length; i++ ) {
final ValuedModelPart attributeMapping = getEmbeddedPart( embeddableMappingType, i );
if ( attributeMapping instanceof SelectableMapping ) {
@@ -312,13 +311,7 @@ private static void convertedBasicValueToString(
case SqlTypes.MATERIALIZED_BLOB:
// These types need to be serialized as JSON string, and for efficiency uses appendString directly
appender.append( '"' );
- appender.write(
- javaType.unwrap(
- value,
- byte[].class,
- options
- )
- );
+ appender.write( javaType.unwrap( value, byte[].class, options ) );
appender.append( '"' );
break;
case SqlTypes.ARRAY:
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java
index da66ea545d2b..6a6e02774434 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java
@@ -253,6 +253,7 @@ private void createUserDefinedArrayType(
userDefinedArrayType.setArraySqlTypeCode( getDdlTypeCode() );
userDefinedArrayType.setElementTypeName( elementTypeName );
userDefinedArrayType.setElementSqlTypeCode( elementJdbcType.getDefaultSqlTypeCode() );
+ userDefinedArrayType.setElementDdlTypeCode( elementJdbcType.getDdlTypeCode() );
userDefinedArrayType.setArrayLength( columnSize.getArrayLength() == null ? 127 : columnSize.getArrayLength() );
}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java
index 47a97d600962..9f5575a32056 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java
@@ -47,6 +47,8 @@
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.config.ConfigurationHelper;
+import org.hibernate.mapping.AggregateColumn;
+import org.hibernate.mapping.Table;
import org.hibernate.mapping.UserDefinedType;
import org.hibernate.mapping.CheckConstraint;
import org.hibernate.metamodel.mapping.EntityMappingType;
@@ -78,6 +80,7 @@
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOracleDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
+import org.hibernate.tool.schema.internal.StandardTableExporter;
import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.NullType;
@@ -181,6 +184,17 @@ public class OracleDialect extends Dialect {
private final OracleUserDefinedTypeExporter userDefinedTypeExporter = new OracleUserDefinedTypeExporter( this );
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
private final SequenceSupport oracleSequenceSupport = OracleSequenceSupport.getInstance(this);
+ private final StandardTableExporter oracleTableExporter = new StandardTableExporter( this ) {
+ @Override
+ protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
+ final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
+ if ( dialect.getVersion().isBefore( 23, 6 ) && jdbcType.isXml() ) {
+ // ORA-00600 when selecting XML columns that have a check constraint was fixed in 23.6
+ return;
+ }
+ super.applyAggregateColumnCheck( buf, aggregateColumn );
+ }
+ };
// Is it an Autonomous Database Cloud Service?
protected final boolean autonomous;
@@ -589,6 +603,8 @@ public String castPattern(CastType from, CastType to) {
return "to_timestamp_tz(?1,'YYYY-MM-DD HH24:MI:SS.FF9 TZR')";
}
break;
+ case XML:
+ return "xmlparse(document ?1)";
}
return super.castPattern(from, to);
}
@@ -988,6 +1004,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
typeContributions.contributeJdbcType( OracleBooleanJdbcType.INSTANCE );
}
typeContributions.contributeJdbcType( OracleXmlJdbcType.INSTANCE );
+ typeContributions.contributeJdbcTypeConstructor( OracleXmlArrayJdbcTypeConstructor.INSTANCE );
if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) {
typeContributions.contributeJdbcType( OracleJdbcHelper.getStructJdbcType( serviceRegistry ) );
}
@@ -1132,6 +1149,11 @@ public SequenceSupport getSequenceSupport() {
return oracleSequenceSupport;
}
+ @Override
+ public Exporter getTableExporter() {
+ return oracleTableExporter;
+ }
+
@Override
public String getQuerySequencesString() {
return "select * from all_sequences";
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonArrayJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonArrayJdbcType.java
index aac07cb6fa3e..a722c61d2b45 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonArrayJdbcType.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleJsonArrayJdbcType.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.dialect;
+import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@@ -20,6 +21,11 @@ public OracleJsonArrayJdbcType(JdbcType elementJdbcType) {
super( elementJdbcType );
}
+ @Override
+ public int getDdlTypeCode() {
+ return SqlTypes.JSON;
+ }
+
@Override
public String toString() {
return "OracleJsonJdbcType";
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java
index 6b6325454101..5f6441b1e52f 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleUserDefinedTypeExporter.java
@@ -4,8 +4,6 @@
*/
package org.hibernate.dialect;
-import java.util.Locale;
-
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.QualifiedName;
@@ -16,18 +14,16 @@
import org.hibernate.type.SqlTypes;
import static java.sql.Types.BOOLEAN;
-import static org.hibernate.type.SqlTypes.BIGINT;
import static org.hibernate.type.SqlTypes.BINARY;
+import static org.hibernate.type.SqlTypes.BIT;
+import static org.hibernate.type.SqlTypes.BLOB;
import static org.hibernate.type.SqlTypes.DATE;
-import static org.hibernate.type.SqlTypes.INTEGER;
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
-import static org.hibernate.type.SqlTypes.SMALLINT;
import static org.hibernate.type.SqlTypes.TABLE;
import static org.hibernate.type.SqlTypes.TIME;
import static org.hibernate.type.SqlTypes.TIMESTAMP;
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
-import static org.hibernate.type.SqlTypes.TINYINT;
import static org.hibernate.type.SqlTypes.UUID;
import static org.hibernate.type.SqlTypes.VARBINARY;
@@ -61,11 +57,13 @@ public String[] getSqlCreateStrings(
}
final int arrayLength = userDefinedType.getArrayLength();
final Integer elementSqlTypeCode = userDefinedType.getElementSqlTypeCode();
+ final Integer elementDdlTypeCode = userDefinedType.getElementDdlTypeCode();
final String jsonTypeName = metadata.getDatabase().getTypeConfiguration().getDdlTypeRegistry().getTypeName(
SqlTypes.JSON,
dialect
);
- final String valueExpression = determineValueExpression( "t.value", elementSqlTypeCode, elementType );
+ final String valueExpression = determineValueExpression( "t.value", elementSqlTypeCode, elementDdlTypeCode, elementType );
+ final String jsonElementType = determineJsonElementType( elementSqlTypeCode, elementDdlTypeCode, elementType );
return new String[] {
"create or replace type " + arrayTypeName + " as varying array(" + arrayLength + ") of " + elementType,
"create or replace function " + arrayTypeName + "_cmp(a in " + arrayTypeName +
@@ -266,7 +264,7 @@ public String[] getSqlCreateStrings(
"res " + arrayTypeName + ":=" + arrayTypeName + "(); begin " +
"if arr is null then return null; end if; " +
"select " + valueExpression + " bulk collect into res " +
- "from json_table(arr,'$[*]' columns (value path '$')) t; " +
+ "from json_table(arr,'$[*]' columns (value " + jsonElementType + " path '$')) t; " +
"return res; " +
"end;"
};
@@ -332,17 +330,8 @@ private boolean supportsIfExistsBeforeFunctionName() {
return dialect.getVersion().isSameOrAfter( 23 );
}
- private String determineValueExpression(String expression, int elementSqlTypeCode, String elementType) {
+ private String determineValueExpression(String expression, int elementSqlTypeCode, Integer elementDdlTypeCode, String elementType) {
switch ( elementSqlTypeCode ) {
- case BOOLEAN:
- if ( elementType.toLowerCase( Locale.ROOT ).trim().startsWith( "number" ) ) {
- return "decode(" + expression + ",'true',1,'false',0,null)";
- }
- case TINYINT:
- case SMALLINT:
- case INTEGER:
- case BIGINT:
- return "cast(" + expression + " as " + elementType + ")";
case DATE:
return "to_date(" + expression + ",'YYYY-MM-DD')";
case TIME:
@@ -355,14 +344,47 @@ private String determineValueExpression(String expression, int elementSqlTypeCod
case BINARY:
case VARBINARY:
case LONG32VARBINARY:
- return "hextoraw(" + expression + ")";
+ case BLOB:
+ return "xmlcast(xmlcdata(" + expression + ") as " + elementType + ")";
case UUID:
return "hextoraw(replace(" + expression + ",'-',''))";
+ case BIT:
+ return "decode(" + expression + ",'true',1,'false',0,null)";
+ case BOOLEAN:
+ if ( SqlTypes.isNumericType( elementDdlTypeCode ) ) {
+ return "decode(" + expression + ",'true',1,'false',0,null)";
+ }
+ // Fall-through intended
default:
return expression;
}
}
+ private String determineJsonElementType(Integer elementSqlTypeCode, Integer elementDdlTypeCode, String elementType) {
+ switch ( elementSqlTypeCode ) {
+ case BINARY:
+ case VARBINARY:
+ case LONG32VARBINARY:
+ case BLOB:
+ return "clob";
+ case BOOLEAN:
+ if ( !SqlTypes.isNumericType( elementDdlTypeCode ) ) {
+ return elementType;
+ }
+ // Fall-through intended
+ case BIT:
+ case DATE:
+ case TIME:
+ case TIMESTAMP:
+ case TIMESTAMP_WITH_TIMEZONE:
+ case TIMESTAMP_UTC:
+ case UUID:
+ return "varchar2(4000)";
+ default:
+ return elementType;
+ }
+ }
+
protected String createOrReplaceConcatFunction(String arrayTypeName) {
// Since Oracle has no builtin concat function for varrays and doesn't support varargs,
// we have to create a function with a fixed amount of arguments with default that fits "most" cases.
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleXmlArrayJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleXmlArrayJdbcType.java
new file mode 100644
index 000000000000..fae141abca01
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleXmlArrayJdbcType.java
@@ -0,0 +1,44 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.dialect;
+
+import org.hibernate.type.descriptor.ValueBinder;
+import org.hibernate.type.descriptor.WrapperOptions;
+import org.hibernate.type.descriptor.java.JavaType;
+import org.hibernate.type.descriptor.jdbc.JdbcType;
+import org.hibernate.type.descriptor.jdbc.XmlArrayJdbcType;
+
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+
+/**
+ * @author Christian Beikov
+ */
+public class OracleXmlArrayJdbcType extends XmlArrayJdbcType {
+
+ public OracleXmlArrayJdbcType(JdbcType elementJdbcType) {
+ super( elementJdbcType );
+ }
+
+ @Override
+ public ValueBinder getBinder(JavaType javaType) {
+ // Seems the Oracle JDBC driver doesn't support `setNull(index, Types.SQLXML)`
+ // but it seems that the following works fine
+ return new XmlArrayBinder<>( javaType, this ) {
+ @Override
+ protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
+ st.setNull( index, Types.VARCHAR );
+ }
+
+ @Override
+ protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
+ st.setNull( name, Types.VARCHAR );
+ }
+ };
+ }
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleXmlArrayJdbcTypeConstructor.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleXmlArrayJdbcTypeConstructor.java
new file mode 100644
index 000000000000..c6300dba5f6a
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleXmlArrayJdbcTypeConstructor.java
@@ -0,0 +1,43 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.dialect;
+
+import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
+import org.hibernate.type.BasicType;
+import org.hibernate.type.SqlTypes;
+import org.hibernate.type.descriptor.jdbc.JdbcType;
+import org.hibernate.type.descriptor.jdbc.JdbcTypeConstructor;
+import org.hibernate.type.spi.TypeConfiguration;
+
+/**
+ * Factory for {@link OracleXmlArrayJdbcType}.
+ */
+public class OracleXmlArrayJdbcTypeConstructor implements JdbcTypeConstructor {
+
+ public static final OracleXmlArrayJdbcTypeConstructor INSTANCE = new OracleXmlArrayJdbcTypeConstructor();
+
+ @Override
+ public JdbcType resolveType(
+ TypeConfiguration typeConfiguration,
+ Dialect dialect,
+ BasicType> elementType,
+ ColumnTypeInformation columnTypeInformation) {
+ return resolveType( typeConfiguration, dialect, elementType.getJdbcType(), columnTypeInformation );
+ }
+
+ @Override
+ public JdbcType resolveType(
+ TypeConfiguration typeConfiguration,
+ Dialect dialect,
+ JdbcType elementType,
+ ColumnTypeInformation columnTypeInformation) {
+ return new OracleXmlArrayJdbcType( elementType );
+ }
+
+ @Override
+ public int getDefaultSqlTypeCode() {
+ return SqlTypes.XML_ARRAY;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
index a46cd1331117..3707cee2bcf9 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java
@@ -50,6 +50,8 @@
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.JdbcExceptionHelper;
+import org.hibernate.mapping.AggregateColumn;
+import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
@@ -78,6 +80,8 @@
import org.hibernate.sql.model.internal.OptionalTableUpdate;
import org.hibernate.sql.model.jdbc.OptionalTableUpdateOperation;
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
+import org.hibernate.tool.schema.internal.StandardTableExporter;
+import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
@@ -145,6 +149,17 @@ public class PostgreSQLDialect extends Dialect {
protected final static DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 12 );
private final UniqueDelegate uniqueDelegate = new CreateTableUniqueDelegate(this);
+ private final StandardTableExporter postgresqlTableExporter = new StandardTableExporter( this ) {
+ @Override
+ protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
+ final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
+ if ( jdbcType.isXml() ) {
+ // Requires the use of xmltable which is not supported in check constraints
+ return;
+ }
+ super.applyAggregateColumnCheck( buf, aggregateColumn );
+ }
+ };
protected final PostgreSQLDriverKind driverKind;
private final OptionalTableUpdateStrategy optionalTableUpdateStrategy;
@@ -1474,6 +1489,11 @@ public UniqueDelegate getUniqueDelegate() {
return uniqueDelegate;
}
+ @Override
+ public Exporter getTableExporter() {
+ return postgresqlTableExporter;
+ }
+
/**
* @return {@code true}, but only because we can "batch" truncate
*/
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java
index 8d4a950b621d..c0480ddd415c 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java
@@ -54,8 +54,10 @@
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
import org.hibernate.internal.util.config.ConfigurationHelper;
+import org.hibernate.mapping.AggregateColumn;
import org.hibernate.mapping.CheckConstraint;
import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
import org.hibernate.procedure.internal.SQLServerCallableStatementSupport;
import org.hibernate.procedure.spi.CallableStatementSupport;
@@ -75,6 +77,7 @@
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.internal.OptionalTableUpdate;
import org.hibernate.tool.schema.internal.StandardSequenceExporter;
+import org.hibernate.tool.schema.internal.StandardTableExporter;
import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
@@ -161,6 +164,17 @@ public Size resolveSize(
};
}
};
+ private final StandardTableExporter sqlServerTableExporter = new StandardTableExporter( this ) {
+ @Override
+ protected void applyAggregateColumnCheck(StringBuilder buf, AggregateColumn aggregateColumn) {
+ final JdbcType jdbcType = aggregateColumn.getType().getJdbcType();
+ if ( jdbcType.isXml() ) {
+ // XML columns can't have check constraints
+ return;
+ }
+ super.applyAggregateColumnCheck( buf, aggregateColumn );
+ }
+ };
public SQLServerDialect() {
this( MINIMUM_VERSION );
@@ -1109,6 +1123,11 @@ public UniqueDelegate getUniqueDelegate() {
return uniqueDelegate;
}
+ @Override
+ public Exporter getTableExporter() {
+ return this.sqlServerTableExporter;
+ }
+
@Override
public Exporter getSequenceExporter() {
return exporter == null ? super.getSequenceExporter() : exporter;
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java
index deb1f874ee08..fd5f89646dfb 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java
@@ -15,6 +15,8 @@
import org.hibernate.QueryTimeoutException;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.TypeContributions;
+import org.hibernate.dialect.aggregate.AggregateSupport;
+import org.hibernate.dialect.aggregate.SybaseASEAggregateSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.TopLimitHandler;
@@ -252,6 +254,11 @@ protected SqlAstTranslator buildTranslator(
};
}
+ @Override
+ public AggregateSupport getAggregateSupport() {
+ return SybaseASEAggregateSupport.valueOf( this );
+ }
+
/**
* The Sybase ASE {@code BIT} type does not allow
* null values, so we don't use it.
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/XmlHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/XmlHelper.java
index 34825926c40f..178932707ed7 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/XmlHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/XmlHelper.java
@@ -5,15 +5,16 @@
package org.hibernate.dialect;
-import java.io.IOException;
import java.io.OutputStream;
+import java.lang.reflect.Array;
import java.sql.SQLException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
-import java.util.Base64;
+import java.util.Collections;
import java.util.List;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.hibernate.Internal;
import org.hibernate.engine.spi.LazySessionWrapperOptions;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@@ -24,16 +25,22 @@
import org.hibernate.metamodel.mapping.ValuedModelPart;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.sql.ast.spi.SqlAppender;
+import org.hibernate.type.BasicPluralType;
+import org.hibernate.type.BasicType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
-import org.hibernate.type.descriptor.java.IntegerJavaType;
+import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.JdbcDateJavaType;
import org.hibernate.type.descriptor.java.JdbcTimeJavaType;
import org.hibernate.type.descriptor.java.JdbcTimestampJavaType;
import org.hibernate.type.descriptor.java.OffsetDateTimeJavaType;
+import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.AggregateJdbcType;
+import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
+import org.hibernate.type.descriptor.jdbc.JdbcType;
+import org.hibernate.type.descriptor.jdbc.XmlArrayJdbcType;
import static java.lang.Character.isLetter;
import static java.lang.Character.isLetterOrDigit;
@@ -52,37 +59,10 @@ public class XmlHelper {
public static final String ROOT_TAG = "e";
private static final String START_TAG = "<" + ROOT_TAG + ">";
private static final String END_TAG = "" + ROOT_TAG + ">";
-
- private static Object fromEscapedString(
- JdbcMapping jdbcMapping,
- String string,
- int start,
- int end) {
- final String unescaped = unescape( string, start, end );
- return fromString( jdbcMapping, unescaped, 0, unescaped.length() );
- }
-
- private static Object fromString(
- JdbcMapping jdbcMapping,
- String string,
- int start,
- int end) {
- return jdbcMapping.getJdbcJavaType().fromEncodedString(
- string,
- start,
- end
- );
- }
-
- private static Object fromRawObject(
- JdbcMapping jdbcMapping,
- Object raw,
- WrapperOptions options) {
- return jdbcMapping.getJdbcJavaType().wrap(
- raw,
- options
- );
- }
+ private static final String NULL_TAG = "<" + ROOT_TAG + "/>";
+ private static final String COLLECTION_START_TAG = "";
+ private static final String COLLECTION_END_TAG = "";
+ private static final String EMPTY_COLLECTION_TAG = "";
private static String unescape(String string, int start, int end) {
final StringBuilder sb = new StringBuilder( end - start );
@@ -111,6 +91,14 @@ private static String unescape(String string, int start, int end) {
sb.append( '&' );
i += 4;
}
+ else if ( i + 5 < end
+ && string.charAt( i + 2 ) == 'p'
+ && string.charAt( i + 3 ) == 'o'
+ && string.charAt( i + 4 ) == 's'
+ && string.charAt( i + 5 ) == ';' ) {
+ sb.append( '\'' );
+ i += 5;
+ }
break OUTER;
case 'g':
if ( string.charAt( i + 2 ) == 't' && string.charAt( i + 3 ) == ';' ) {
@@ -118,6 +106,16 @@ private static String unescape(String string, int start, int end) {
i += 3;
}
break OUTER;
+ case 'q':
+ if ( i + 5 < end
+ && string.charAt( i + 2 ) == 'u'
+ && string.charAt( i + 3 ) == 'o'
+ && string.charAt( i + 4 ) == 't'
+ && string.charAt( i + 5 ) == ';' ) {
+ sb.append( '"' );
+ i += 5;
+ }
+ break OUTER;
}
}
throw new IllegalArgumentException( "Illegal XML content: " + string.substring( start, end ) );
@@ -132,37 +130,59 @@ private static String unescape(String string, int start, int end) {
private static Object fromString(
EmbeddableMappingType embeddableMappingType,
String string,
+ boolean returnEmbeddable,
WrapperOptions options,
int selectableIndex,
int start,
- int end) {
- final JdbcMapping jdbcMapping = embeddableMappingType.getJdbcValueSelectable( selectableIndex ).getJdbcMapping();
- switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) {
- case SqlTypes.BOOLEAN:
- case SqlTypes.BIT:
+ int end) throws SQLException {
+ final JdbcMapping jdbcMapping = embeddableMappingType.getJdbcValueSelectable( selectableIndex )
+ .getJdbcMapping();
+ return fromString(
+ jdbcMapping.getMappedJavaType(),
+ jdbcMapping.getJdbcJavaType(),
+ jdbcMapping.getJdbcType(),
+ string,
+ returnEmbeddable,
+ options,
+ start,
+ end
+ );
+ }
+
+ private static Object fromString(
+ JavaType> javaType,
+ JavaType> jdbcJavaType,
+ JdbcType jdbcType,
+ String string,
+ boolean returnEmbeddable,
+ WrapperOptions options,
+ int start,
+ int end) throws SQLException {
+ switch ( jdbcType.getDefaultSqlTypeCode() ) {
case SqlTypes.TINYINT:
case SqlTypes.SMALLINT:
case SqlTypes.INTEGER:
+ if ( jdbcJavaType.getJavaTypeClass() == Boolean.class ) {
+ return jdbcJavaType.wrap( Integer.parseInt( string, start, end, 10 ), options );
+ }
+ else if ( jdbcJavaType instanceof EnumJavaType> ) {
+ return jdbcJavaType.wrap( Integer.parseInt( string, start, end, 10 ), options );
+ }
+ case SqlTypes.BOOLEAN:
+ case SqlTypes.BIT:
case SqlTypes.BIGINT:
case SqlTypes.FLOAT:
case SqlTypes.REAL:
case SqlTypes.DOUBLE:
case SqlTypes.DECIMAL:
case SqlTypes.NUMERIC:
- Class> javaTypeClass = jdbcMapping.getMappedJavaType().getJavaTypeClass();
- if ( javaTypeClass.isEnum() ) {
- return javaTypeClass.getEnumConstants()
- [IntegerJavaType.INSTANCE.fromEncodedString( string, start, end )];
- }
- return fromString(
- jdbcMapping,
+ return jdbcJavaType.fromEncodedString(
string,
start,
end
);
case SqlTypes.DATE:
- return fromRawObject(
- jdbcMapping,
+ return jdbcJavaType.wrap(
JdbcDateJavaType.INSTANCE.fromEncodedString(
string,
start,
@@ -173,8 +193,7 @@ private static Object fromString(
case SqlTypes.TIME:
case SqlTypes.TIME_WITH_TIMEZONE:
case SqlTypes.TIME_UTC:
- return fromRawObject(
- jdbcMapping,
+ return jdbcJavaType.wrap(
JdbcTimeJavaType.INSTANCE.fromEncodedString(
string,
start,
@@ -183,8 +202,7 @@ private static Object fromString(
options
);
case SqlTypes.TIMESTAMP:
- return fromRawObject(
- jdbcMapping,
+ return jdbcJavaType.wrap(
JdbcTimestampJavaType.INSTANCE.fromEncodedString(
string,
start,
@@ -194,8 +212,7 @@ private static Object fromString(
);
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
case SqlTypes.TIMESTAMP_UTC:
- return fromRawObject(
- jdbcMapping,
+ return jdbcJavaType.wrap(
OffsetDateTimeJavaType.INSTANCE.fromEncodedString(
string,
start,
@@ -207,19 +224,53 @@ private static Object fromString(
case SqlTypes.VARBINARY:
case SqlTypes.LONGVARBINARY:
case SqlTypes.LONG32VARBINARY:
+ case SqlTypes.BLOB:
+ case SqlTypes.MATERIALIZED_BLOB:
+ return jdbcJavaType.wrap(
+ PrimitiveByteArrayJavaType.INSTANCE.fromEncodedString(
+ string,
+ start,
+ end
+ ),
+ options
+ );
case SqlTypes.UUID:
- return fromRawObject(
- jdbcMapping,
- Base64.getDecoder().decode( string.substring( start, end ) ),
+ return jdbcJavaType.wrap(
+ PrimitiveByteArrayJavaType.INSTANCE.fromString(
+ string.substring( start, end ).replace( "-", "" )
+ ),
options
);
+ case SqlTypes.CHAR:
+ case SqlTypes.NCHAR:
+ case SqlTypes.VARCHAR:
+ case SqlTypes.NVARCHAR:
+ if ( jdbcJavaType.getJavaTypeClass() == Boolean.class && end == start + 1 ) {
+ return jdbcJavaType.wrap( string.charAt( start ), options );
+ }
default:
- return fromEscapedString(
- jdbcMapping,
- string,
- start,
- end
- );
+ if ( jdbcType instanceof AggregateJdbcType aggregateJdbcType ) {
+ final Object[] subValues = aggregateJdbcType.extractJdbcValues(
+ CharSequenceHelper.subSequence(
+ string,
+ start,
+ end
+ ),
+ options
+ );
+ if ( returnEmbeddable ) {
+ final StructAttributeValues subAttributeValues = StructHelper.getAttributeValues(
+ aggregateJdbcType.getEmbeddableMappingType(),
+ subValues,
+ options
+ );
+ final EmbeddableMappingType embeddableMappingType = aggregateJdbcType.getEmbeddableMappingType();
+ return instantiate( embeddableMappingType, subAttributeValues, options.getSessionFactory() ) ;
+ }
+ return subValues;
+ }
+ final String unescaped = unescape( string, start, end );
+ return jdbcJavaType.fromEncodedString( unescaped, 0, unescaped.length() );
}
}
@@ -228,8 +279,18 @@ public static X fromString(
String string,
boolean returnEmbeddable,
WrapperOptions options) throws SQLException {
- if ( !string.startsWith( START_TAG ) || !string.endsWith( END_TAG ) ) {
- throw new IllegalArgumentException( "Illegal XML for struct: " + string );
+ if ( NULL_TAG.equals( string ) ) {
+ return null;
+ }
+ int contentEnd = string.length() - 1;
+ while ( contentEnd >= 0 ) {
+ if ( !Character.isWhitespace( string.charAt( contentEnd ) ) ) {
+ break;
+ }
+ contentEnd--;
+ }
+ if ( !string.startsWith( START_TAG ) || !string.regionMatches( contentEnd - END_TAG.length()+ 1, END_TAG, 0, END_TAG.length() ) ) {
+ throw new IllegalArgumentException( "XML not properly formatted: " + string );
}
int end;
final Object[] array;
@@ -243,7 +304,7 @@ public static X fromString(
array = new Object[embeddableMappingType.getJdbcValueCount() + ( embeddableMappingType.isPolymorphic() ? 1 : 0 )];
end = fromString( embeddableMappingType, string, returnEmbeddable, options, array, START_TAG.length() );
}
- assert end + END_TAG.length() == string.length();
+ assert end + END_TAG.length() == contentEnd + 1;
if ( returnEmbeddable ) {
final StructAttributeValues attributeValues = StructHelper.getAttributeValues( embeddableMappingType, array, options );
@@ -254,6 +315,45 @@ public static X fromString(
return (X) array;
}
+ public static X arrayFromString(
+ JavaType javaType,
+ XmlArrayJdbcType xmlArrayJdbcType,
+ String string,
+ WrapperOptions options) throws SQLException {
+ if ( string == null ) {
+ return null;
+ }
+ else if ( EMPTY_COLLECTION_TAG.equals( string ) ) {
+ return javaType.wrap( Collections.emptyList(), options );
+ }
+ else if ( !string.startsWith( COLLECTION_START_TAG ) || !string.endsWith( COLLECTION_END_TAG ) ) {
+ throw new IllegalArgumentException( "Illegal XML for array: " + string );
+ }
+ final JavaType> elementJavaType = ((BasicPluralJavaType>) javaType).getElementJavaType();
+ final Class> preferredJavaTypeClass = xmlArrayJdbcType.getElementJdbcType().getPreferredJavaTypeClass( options );
+ final JavaType> jdbcJavaType;
+ if ( preferredJavaTypeClass == null || preferredJavaTypeClass == elementJavaType.getJavaTypeClass() ) {
+ jdbcJavaType = elementJavaType;
+ }
+ else {
+ jdbcJavaType = options.getSessionFactory().getTypeConfiguration().getJavaTypeRegistry()
+ .resolveDescriptor( preferredJavaTypeClass );
+ }
+ final ArrayList