Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -384,16 +384,19 @@ public interface SchemaToolingSettings {
* <p>
* The default value is {@code /import.sql}.
*
* @deprecated The JPA-standard setting {@link #JAKARTA_HBM2DDL_CREATE_SCRIPT_SOURCE} is now preferred.
* @deprecated The JPA-standard setting {@link #JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE} is now preferred.
*/
@Deprecated
String HBM2DDL_IMPORT_FILES = "hibernate.hbm2ddl.import_files";

/**
* Specifies if the default {@code /import.sql} script file should not be executed
* when {@link #HBM2DDL_IMPORT_FILES} is not specified and {@value #HBM2DDL_AUTO} is set to {@code create} or {@code create-drop}.
* Specifies that the default {@code /import.sql} script file should not be executed
* when {@link #HBM2DDL_IMPORT_FILES} is not specified and {@value #HBM2DDL_AUTO}
* is set to {@code create} or {@code create-drop}.
*
* The default value is {@code false}.
* @settingDefault {@code false}.
*
* @since 6.6
*/
String HBM2DDL_SKIP_DEFAULT_IMPORT_FILE = "hibernate.hbm2ddl.skip_default_import_file";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public interface SchemaManager extends jakarta.persistence.SchemaManager {
void validateMappedObjects();

/**
* Truncate the database tables mapped by Hibernate entities, and
* then re-import initial data from any configured
* Truncate the database tables mapped by Hibernate entities, and then
* reimport initial data from {@code /import.sql} and any other configured
* {@linkplain org.hibernate.cfg.AvailableSettings#JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE
* load script}.
* <p>
Expand All @@ -72,4 +72,16 @@ public interface SchemaManager extends jakarta.persistence.SchemaManager {
* @apiNote This operation is a synonym for {@link #truncate}.
*/
void truncateMappedObjects();

/**
* Populate the database by executing {@code /import.sql} and any other configured
* {@linkplain org.hibernate.cfg.AvailableSettings#JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE
* load script}.
* <p>
* Programmatic way to run {@link org.hibernate.tool.schema.spi.SchemaPopulator}.
*
* @since 7.0
*/
@Incubating
void populate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ public void truncateMappedObjects() {
);
}

@Override
public void populate() {
Map<String, Object> properties = new HashMap<>( sessionFactory.getProperties() );
properties.put( AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION, Action.POPULATE );
properties.put( AvailableSettings.JAKARTA_HBM2DDL_SCRIPTS_ACTION, Action.NONE );
SchemaManagementToolCoordinator.process(
metadata,
sessionFactory.getServiceRegistry(),
properties,
action -> {}
);
}

@Override
public void create(boolean createSchemas) {
exportMappedObjects( createSchemas );
Expand Down
65 changes: 34 additions & 31 deletions hibernate-core/src/main/java/org/hibernate/tool/schema/Action.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,18 @@ public enum Action {
*
* @since 6.2
*/
TRUNCATE;
TRUNCATE,
/**
* Populate an existing schema by executing {@code /import.sql} and other scripts specified
* via {@value org.hibernate.cfg.SchemaToolingSettings#JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE}.
*
* @apiNote This action is not defined by JPA.
*
* @see org.hibernate.tool.schema.spi.SchemaPopulator
*
* @since 7.0
*/
POPULATE;

/**
* @see #NONE
Expand Down Expand Up @@ -135,6 +146,10 @@ public enum Action {
* @see #UPDATE
*/
public static final String ACTION_UPDATE = "update";
/**
* @see #POPULATE
*/
public static final String ACTION_POPULATE = "populate";

/**
* @see #NONE
Expand All @@ -159,43 +174,31 @@ public enum Action {
* or {@value org.hibernate.cfg.AvailableSettings#JAKARTA_HBM2DDL_SCRIPTS_ACTION}.
*/
public String getExternalJpaName() {
switch (this) {
case NONE:
return SPEC_ACTION_NONE;
case CREATE_ONLY:
return SPEC_ACTION_CREATE;
case DROP:
return SPEC_ACTION_DROP;
case CREATE:
return SPEC_ACTION_DROP_AND_CREATE;
default:
return null;
}
return switch ( this ) {
case NONE -> SPEC_ACTION_NONE;
case CREATE_ONLY -> SPEC_ACTION_CREATE;
case DROP -> SPEC_ACTION_DROP;
case CREATE -> SPEC_ACTION_DROP_AND_CREATE;
default -> null;
};
}

/**
* The string configuration value identifying this action in old-school Hibernate
* configuration via {@value org.hibernate.cfg.AvailableSettings#HBM2DDL_AUTO}.
*/
public String getExternalHbm2ddlName() {
switch (this) {
case NONE:
return ACTION_NONE;
case CREATE_ONLY:
return ACTION_CREATE_ONLY;
case DROP:
return ACTION_DROP;
case CREATE:
return ACTION_CREATE;
case CREATE_DROP:
return ACTION_CREATE_THEN_DROP;
case VALIDATE:
return ACTION_VALIDATE;
case UPDATE:
return ACTION_UPDATE;
default:
return null;
}
return switch ( this ) {
case NONE -> ACTION_NONE;
case CREATE_ONLY -> ACTION_CREATE_ONLY;
case DROP -> ACTION_DROP;
case CREATE -> ACTION_CREATE;
case CREATE_DROP -> ACTION_CREATE_THEN_DROP;
case VALIDATE -> ACTION_VALIDATE;
case UPDATE -> ACTION_UPDATE;
case POPULATE -> ACTION_POPULATE;
default -> null;
};
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.tool.schema.internal;

import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.internal.FormatStyle;
import org.hibernate.engine.jdbc.internal.Formatter;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.tool.schema.internal.exec.ScriptSourceInputFromUrl;
import org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl;
import org.hibernate.tool.schema.spi.ExecutionOptions;
import org.hibernate.tool.schema.spi.GenerationTarget;
import org.hibernate.tool.schema.spi.SchemaManagementException;
import org.hibernate.tool.schema.spi.ScriptSourceInput;
import org.hibernate.tool.schema.spi.SqlScriptCommandExtractor;

import java.net.URL;
import java.util.Map;

import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_CHARSET_NAME;
import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_IMPORT_FILES;
import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_LOAD_SCRIPT_SOURCE;
import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_SKIP_DEFAULT_IMPORT_FILE;
import static org.hibernate.cfg.SchemaToolingSettings.JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE;
import static org.hibernate.internal.util.config.ConfigurationHelper.getBoolean;
import static org.hibernate.internal.util.config.ConfigurationHelper.getString;
import static org.hibernate.tool.schema.internal.Helper.applyScript;
import static org.hibernate.tool.schema.internal.Helper.interpretScriptSourceSetting;

/**
* Handles population from {@value #DEFAULT_IMPORT_FILE} and other scripts.
*/
public abstract class AbstractSchemaPopulator {

public static final String DEFAULT_IMPORT_FILE = "/import.sql";

abstract ClassLoaderService getClassLoaderService();

void applyImportSources(
ExecutionOptions options,
SqlScriptCommandExtractor commandExtractor,
boolean format,
Dialect dialect,
GenerationTarget... targets) {

final Formatter formatter = getImportScriptFormatter(format);

boolean hasDefaultImportFileScriptBeenExecuted = applyImportScript(
options,
commandExtractor,
dialect,
formatter,
targets
);
applyImportFiles(
options,
commandExtractor,
dialect,
formatter,
hasDefaultImportFileScriptBeenExecuted ? "" : getDefaultImportFile( options ),
targets
);
}

private String getDefaultImportFile(ExecutionOptions options) {
return skipDefaultFileImport( options ) ? "" : DEFAULT_IMPORT_FILE;
}

private static boolean skipDefaultFileImport(ExecutionOptions options) {
return getBoolean( HBM2DDL_SKIP_DEFAULT_IMPORT_FILE, options.getConfigurationValues(), false );
}

/**
* In principle, we should format the commands in the import script if the
* {@code format} parameter is {@code true}, and since it's supposed to be
* a list of DML statements, we should use the {@linkplain FormatStyle#BASIC
* basic DML formatter} to do that. However, in practice we don't really know
* much about what this file contains, and we have never formatted it in the
* past, so there's no compelling reason to start now. In fact, if we have
* lists of many {@code insert} statements on the same table, which is what
* we typically expect, it's probably better to not format.
*/
private static Formatter getImportScriptFormatter(boolean format) {

Check notice

Code scanning / CodeQL

Useless parameter Note

The parameter 'format' is never used.
// return format ? FormatStyle.BASIC.getFormatter() : FormatStyle.NONE.getFormatter();
return FormatStyle.NONE.getFormatter();
}

/**
* Handles import scripts specified using
* {@link org.hibernate.cfg.AvailableSettings#HBM2DDL_IMPORT_FILES}.
*
* @return {@code true} if the legacy {@linkplain #DEFAULT_IMPORT_FILE default import file}
* was one of the listed imported files that were executed
*/
private boolean applyImportScript(
ExecutionOptions options,
SqlScriptCommandExtractor commandExtractor,
Dialect dialect,
Formatter formatter,
GenerationTarget[] targets) {
final Object importScriptSetting = getImportScriptSetting( options );
if ( importScriptSetting != null ) {
final ScriptSourceInput importScriptInput =
interpretScriptSourceSetting( importScriptSetting, getClassLoaderService(), getCharsetName( options ) );
applyScript(
options,
commandExtractor,
dialect,
importScriptInput,
formatter,
targets
);
return containsDefaultImportFile( importScriptInput, options );
}
else {
return false;
}
}

private boolean containsDefaultImportFile(ScriptSourceInput importScriptInput,ExecutionOptions options ) {
if ( skipDefaultFileImport( options ) ) {
return false;
}
final URL defaultImportFileUrl = getClassLoaderService().locateResource( DEFAULT_IMPORT_FILE );
return defaultImportFileUrl != null && importScriptInput.containsScript( defaultImportFileUrl );
}

/**
* Handles import scripts specified using
* {@link org.hibernate.cfg.AvailableSettings#JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE}.
*/
private void applyImportFiles(
ExecutionOptions options,
SqlScriptCommandExtractor commandExtractor,
Dialect dialect,
Formatter formatter,
String defaultImportFile,
GenerationTarget[] targets) {
final String[] importFiles =
StringHelper.split( ",",
getString( HBM2DDL_IMPORT_FILES, options.getConfigurationValues(), defaultImportFile ) );
final String charsetName = getCharsetName( options );
final ClassLoaderService classLoaderService = getClassLoaderService();
for ( String currentFile : importFiles ) {
final String resourceName = currentFile.trim();
if ( !resourceName.isEmpty() ) { //skip empty resource names
applyScript(
options,
commandExtractor,
dialect,
interpretLegacyImportScriptSetting( resourceName, classLoaderService, charsetName ),
formatter,
targets
);
}
}
}

private ScriptSourceInput interpretLegacyImportScriptSetting(
String resourceName,
ClassLoaderService classLoaderService,
String charsetName) {
try {
final URL resourceUrl = classLoaderService.locateResource( resourceName );
return resourceUrl == null
? ScriptSourceInputNonExistentImpl.INSTANCE
: new ScriptSourceInputFromUrl( resourceUrl, charsetName );
}
catch (Exception e) {
throw new SchemaManagementException( "Error resolving legacy import resource : " + resourceName, e );
}
}

/**
* @see org.hibernate.cfg.AvailableSettings#HBM2DDL_CHARSET_NAME
*/
private static String getCharsetName(ExecutionOptions options) {
return (String) options.getConfigurationValues().get( HBM2DDL_CHARSET_NAME );
}

/**
* @see org.hibernate.cfg.AvailableSettings#JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE
*
* @return a {@link java.io.Reader} or a string URL
*/
private static Object getImportScriptSetting(ExecutionOptions options) {
final Map<String, Object> configuration = options.getConfigurationValues();
final Object importScriptSetting = configuration.get( HBM2DDL_LOAD_SCRIPT_SOURCE );
return importScriptSetting == null
? configuration.get( JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE )
: importScriptSetting;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.hibernate.tool.schema.spi.SchemaManagementException;
import org.hibernate.tool.schema.spi.SchemaManagementTool;
import org.hibernate.tool.schema.spi.SchemaMigrator;
import org.hibernate.tool.schema.spi.SchemaPopulator;
import org.hibernate.tool.schema.spi.SchemaTruncator;
import org.hibernate.tool.schema.spi.SchemaValidator;
import org.hibernate.tool.schema.spi.TargetDescriptor;
Expand Down Expand Up @@ -101,6 +102,11 @@ public SchemaTruncator getSchemaTruncator(Map<String,Object> options) {
return new SchemaTruncatorImpl( this, getSchemaFilterProvider( options ).getTruncatorFilter() );
}

@Override
public SchemaPopulator getSchemaPopulator(Map<String, Object> options) {
return new SchemaPopulatorImpl( this );
}

@Override
public SchemaMigrator getSchemaMigrator(Map<String,Object> options) {
final SchemaFilter migrateFilter = getSchemaFilterProvider( options ).getMigrateFilter();
Expand Down
Loading
Loading