diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java index 593d1a20fc1c..c5885b585df1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java @@ -117,6 +117,10 @@ public static void bindDefaults(MetadataBuildingContext context) { QueryBinder.bindNamedStoredProcedureQuery( queryRegistration.configuration(), context, true ); } ); + globalRegistrations.getDatabaseObjectRegistrations().forEach( databaseObjectRegistration -> + AuxiliaryDatabaseObjectBinder.processAuxiliaryDatabaseObject( context, databaseObjectRegistration ) + ); + } private static ModelsContext modelsContext(MetadataBuildingContext context) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AuxiliaryDatabaseObjectBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AuxiliaryDatabaseObjectBinder.java new file mode 100644 index 000000000000..96a5d307b8db --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AuxiliaryDatabaseObjectBinder.java @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.model.internal; + +import org.hibernate.MappingException; +import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; +import org.hibernate.boot.model.relational.SimpleAuxiliaryDatabaseObject; +import org.hibernate.boot.models.spi.DatabaseObjectRegistration; +import org.hibernate.boot.models.spi.DialectScopeRegistration; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.models.internal.util.StringHelper; + +public class AuxiliaryDatabaseObjectBinder { + public static void processAuxiliaryDatabaseObject( + MetadataBuildingContext context, + DatabaseObjectRegistration databaseObjectRegistration) { + final AuxiliaryDatabaseObject auxDbObject; + + if ( StringHelper.isNotEmpty( databaseObjectRegistration.definition()) ) { + try { + auxDbObject = (AuxiliaryDatabaseObject) + context.getBootstrapContext().getClassLoaderService() + .classForName( databaseObjectRegistration.definition() ) + .newInstance(); + } + catch (ClassLoadingException cle) { + throw cle; + } + catch (Exception e) { + throw new MappingException( + String.format( + "Unable to instantiate custom AuxiliaryDatabaseObject class [%s]", + databaseObjectRegistration.definition() + ) + ); + } + } + else { + auxDbObject = new SimpleAuxiliaryDatabaseObject( + context.getMetadataCollector().getDatabase().getDefaultNamespace(), + databaseObjectRegistration.create(), + databaseObjectRegistration.drop(), + null + ); + } + + if ( !databaseObjectRegistration.dialectScopes().isEmpty() ) { + if ( auxDbObject instanceof AuxiliaryDatabaseObject.Expandable expandable ) { + for ( DialectScopeRegistration dialectScopeRegistration : databaseObjectRegistration.dialectScopes() ) { + expandable.addDialectScope( dialectScopeRegistration.name()); + } + } + else { + // error? warn? + } + } + + context.getMetadataCollector().getDatabase().addAuxiliaryDatabaseObject( auxDbObject ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/internal/DomainModelCategorizationCollector.java b/hibernate-core/src/main/java/org/hibernate/boot/models/internal/DomainModelCategorizationCollector.java index d4dee6f4f442..c70ac5282d69 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/internal/DomainModelCategorizationCollector.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/internal/DomainModelCategorizationCollector.java @@ -85,6 +85,7 @@ public void apply(JaxbEntityMappingsImpl jaxbRoot, XmlDocumentContext xmlDocumen getGlobalRegistrations().collectQueryReferences( jaxbRoot, xmlDocumentContext ); + getGlobalRegistrations().collectDataBaseObject( jaxbRoot.getDatabaseObjects() ); // todo (7.0) : named graphs? } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/internal/GlobalRegistrationsImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/models/internal/GlobalRegistrationsImpl.java index 8d7f51ef28e9..674c4e1a73ec 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/internal/GlobalRegistrationsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/internal/GlobalRegistrationsImpl.java @@ -24,6 +24,8 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbConfigurationParameterImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbConverterImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbConverterRegistrationImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbDatabaseObjectImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbDatabaseObjectScopeImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddableInstantiatorRegistrationImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListenerImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; @@ -53,6 +55,8 @@ import org.hibernate.boot.models.spi.CompositeUserTypeRegistration; import org.hibernate.boot.models.spi.ConversionRegistration; import org.hibernate.boot.models.spi.ConverterRegistration; +import org.hibernate.boot.models.spi.DatabaseObjectRegistration; +import org.hibernate.boot.models.spi.DialectScopeRegistration; import org.hibernate.boot.models.spi.EmbeddableInstantiatorRegistration; import org.hibernate.boot.models.spi.FilterDefRegistration; import org.hibernate.boot.models.spi.GenericGeneratorRegistration; @@ -144,6 +148,8 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations, GlobalRegis private Map namedNativeQueryRegistrations; private Map namedStoredProcedureQueryRegistrations; + private List databaseObjectRegistrations; + public GlobalRegistrationsImpl(ModelsContext sourceModelContext, BootstrapContext bootstrapContext) { this.sourceModelContext = sourceModelContext; this.bootstrapContext = bootstrapContext; @@ -242,9 +248,13 @@ public Map getNamedNativeQueryRegistration @Override public Map getNamedStoredProcedureQueryRegistrations() { - return namedStoredProcedureQueryRegistrations== null ? emptyMap() : namedStoredProcedureQueryRegistrations; + return namedStoredProcedureQueryRegistrations == null ? emptyMap() : namedStoredProcedureQueryRegistrations; } + @Override + public List getDatabaseObjectRegistrations() { + return databaseObjectRegistrations == null ? emptyList() : databaseObjectRegistrations; + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // JavaTypeRegistration @@ -1314,4 +1324,34 @@ private List extractQueryHints(JaxbQueryHintContainer jaxbQuery) { } return hints; } + + public void collectDataBaseObject(List databaseObjects) { + if ( isEmpty( databaseObjects ) ) { + return; + } + + if ( databaseObjectRegistrations == null ) { + databaseObjectRegistrations = new ArrayList<>(); + } + + for ( JaxbDatabaseObjectImpl jaxbDatabaseObject : databaseObjects ) { + final JaxbDatabaseObjectImpl.JaxbDefinitionImpl definition = jaxbDatabaseObject.getDefinition(); + final List dialectScopes = jaxbDatabaseObject.getDialectScopes(); + final List scopeRegistrations = new ArrayList<>(dialectScopes.size()); + for ( JaxbDatabaseObjectScopeImpl dialectScope : dialectScopes ) { + scopeRegistrations.add( + new DialectScopeRegistration( + dialectScope.getName(), + dialectScope.getContent(), + dialectScope.getMinimumVersion(), + dialectScope.getMaximumVersion() ) + ); + } + databaseObjectRegistrations.add( new DatabaseObjectRegistration( + jaxbDatabaseObject.getCreate(), + jaxbDatabaseObject.getDrop(), + definition != null ? definition.getClazz() : null, + scopeRegistrations ) ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/spi/DatabaseObjectRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/spi/DatabaseObjectRegistration.java new file mode 100644 index 000000000000..da7a423022ee --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/spi/DatabaseObjectRegistration.java @@ -0,0 +1,10 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.models.spi; + +import java.util.List; + +public record DatabaseObjectRegistration(String create, String drop, String definition, List dialectScopes ) { +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/spi/DialectScopeRegistration.java b/hibernate-core/src/main/java/org/hibernate/boot/models/spi/DialectScopeRegistration.java new file mode 100644 index 000000000000..03ae2dc7b0d7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/spi/DialectScopeRegistration.java @@ -0,0 +1,8 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.boot.models.spi; + +public record DialectScopeRegistration(String name, String content, String minimumVersion, String maximumVersion) { +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/spi/GlobalRegistrations.java b/hibernate-core/src/main/java/org/hibernate/boot/models/spi/GlobalRegistrations.java index bda22b484671..f6b416418477 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/spi/GlobalRegistrations.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/spi/GlobalRegistrations.java @@ -52,6 +52,8 @@ public interface GlobalRegistrations { Map getNamedStoredProcedureQueryRegistrations(); + List getDatabaseObjectRegistrations(); + // todo : named entity graphs T as(Class type); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java index 1f5631088762..901daebd1f28 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java @@ -215,8 +215,8 @@ public void initSessionFactory() { metadataSources.addInputStream( getClass().getResourceAsStream( "implicit-file-level-catalog-and-schema.hbm.xml" ) ); metadataSources.addInputStream( getClass().getResourceAsStream( "no-file-level-catalog-and-schema.orm.xml" ) ); metadataSources.addInputStream( getClass().getResourceAsStream( "no-file-level-catalog-and-schema.hbm.xml" ) ); - metadataSources.addInputStream( getClass().getResourceAsStream( "database-object-using-catalog-placeholder.hbm.xml" ) ); - metadataSources.addInputStream( getClass().getResourceAsStream( "database-object-using-schema-placeholder.hbm.xml" ) ); + metadataSources.addInputStream( getClass().getResourceAsStream( "database-object-using-catalog-placeholder.orm.xml" ) ); + metadataSources.addInputStream( getClass().getResourceAsStream( "database-object-using-schema-placeholder.orm.xml" ) ); if ( configuredXmlMappingPath != null ) { metadataSources.addInputStream( getClass().getResourceAsStream( configuredXmlMappingPath ) ); } diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/boot/database/qualfiedTableNaming/database-object-using-catalog-placeholder.orm.xml b/hibernate-core/src/test/resources/org/hibernate/orm/test/boot/database/qualfiedTableNaming/database-object-using-catalog-placeholder.orm.xml new file mode 100644 index 000000000000..0d8b8a207074 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/boot/database/qualfiedTableNaming/database-object-using-catalog-placeholder.orm.xml @@ -0,0 +1,26 @@ + + + + + + + CREATE OR REPLACE FUNCTION ${catalog}.catalogPrefixedAuxObject() + RETURNS varchar AS + $BODY$ + BEGIN + SELECT 'test'; + END; + $BODY$ + LANGUAGE plpgsql + + DROP FUNCTION ${catalog}.catalogPrefixedAuxObject() + + diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/boot/database/qualfiedTableNaming/database-object-using-schema-placeholder.orm.xml b/hibernate-core/src/test/resources/org/hibernate/orm/test/boot/database/qualfiedTableNaming/database-object-using-schema-placeholder.orm.xml new file mode 100644 index 000000000000..56559b2bc226 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/boot/database/qualfiedTableNaming/database-object-using-schema-placeholder.orm.xml @@ -0,0 +1,27 @@ + + + + + + + CREATE OR REPLACE FUNCTION ${schema}.schemaPrefixedAuxObject() + RETURNS varchar AS + $BODY$ + BEGIN + SELECT 'test'; + END; + $BODY$ + LANGUAGE plpgsql + + DROP FUNCTION ${schema}.schemaPrefixedAuxObject() + + + \ No newline at end of file