HHH-11817 Allow schema-export commands written to file to truncate in addition to current appending

This commit is contained in:
Andrea Boriero 2021-06-16 16:03:50 +02:00 committed by Yoann Rodière
parent 107849c3c8
commit 8fc45a9004
8 changed files with 120 additions and 26 deletions

View File

@ -887,6 +887,10 @@ For cases where the `javax.persistence.schema-generation.scripts.action` value i
`*javax.persistence.schema-generation.scripts.drop-target*`:: `*javax.persistence.schema-generation.scripts.drop-target*`::
For cases where the `javax.persistence.schema-generation.scripts.action` value indicates that schema dropping commands should be written to DDL script file, `javax.persistence.schema-generation.scripts.drop-target` specifies either a `java.io.Writer` configured for output of the DDL script or a string specifying the file URL for the DDL script. For cases where the `javax.persistence.schema-generation.scripts.action` value indicates that schema dropping commands should be written to DDL script file, `javax.persistence.schema-generation.scripts.drop-target` specifies either a `java.io.Writer` configured for output of the DDL script or a string specifying the file URL for the DDL script.
`*hibernate.hbm2ddl.schema-generation.script.append*` (e.g. `true` (default value) or `false`)::
For cases where the `javax.persistence.schema-generation.scripts.action` value indicates that schema commands should be written to DDL script file, `hibernate.hbm2ddl.schema-generation.script.append` specifies if schema commands should be appended to the end of the file rather than written at the beginning of the file.
Values are `true` for appending schema commands to the end of the file, `false` for writing achema commands at the beginning of the file.
`*javax.persistence.hibernate.hbm2ddl.import_files*` (e.g. `import.sql` (default value)):: `*javax.persistence.hibernate.hbm2ddl.import_files*` (e.g. `import.sql` (default value))::
Comma-separated names of the optional files containing SQL DML statements executed during the `SessionFactory` creation. Comma-separated names of the optional files containing SQL DML statements executed during the `SessionFactory` creation.
File order matters, the statements of a given file are executed before the statements of the following one. File order matters, the statements of a given file are executed before the statements of the following one.

View File

@ -1588,6 +1588,16 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
@SuppressWarnings("JavaDoc") @SuppressWarnings("JavaDoc")
String HBM2DDL_SCRIPTS_CREATE_TARGET = "javax.persistence.schema-generation.scripts.create-target"; String HBM2DDL_SCRIPTS_CREATE_TARGET = "javax.persistence.schema-generation.scripts.create-target";
/**
* For cases where the {@value #HBM2DDL_SCRIPTS_ACTION} value indicates that schema commands should
* be written to DDL script file, specifies if schema commands should be appended to the end of the file rather than written at the beginning of the file.
*
* Values are: {@code true} for appending schema commands to the end of the file, {@code false} for writing schema commands at the beginning.
*
* The default value is {@code true}
*/
String HBM2DDL_SCRIPTS_CREATE_APPEND = "hibernate.hbm2ddl.schema-generation.script.append";
/** /**
* For cases where the {@value #HBM2DDL_SCRIPTS_ACTION} value indicates that schema drop commands should * For cases where the {@value #HBM2DDL_SCRIPTS_ACTION} value indicates that schema drop commands should
* be written to DDL script file, {@value #HBM2DDL_SCRIPTS_DROP_TARGET} specifies either a * be written to DDL script file, {@value #HBM2DDL_SCRIPTS_DROP_TARGET} specifies either a

View File

@ -135,6 +135,7 @@ else if ( actionText.equalsIgnoreCase( "drop-and-create" ) ) {
} }
} }
boolean append = true;
boolean haltOnError = false; boolean haltOnError = false;
boolean format = false; boolean format = false;
boolean manageNamespaces = false; boolean manageNamespaces = false;
@ -159,6 +160,18 @@ public SchemaExport setOutputFile(String filename) {
return this; return this;
} }
/**
* For generating a export script file, by default the content will be appended at the begin or end of the file.
*
* The sql will be written at the beginning of the file rather append to the end.
*
* @return this
*/
public SchemaExport setOverrideOutputFileContent() {
append = false;
return this;
}
/** /**
* Comma-separated list of resource names to use for database init commands on create. * Comma-separated list of resource names to use for database init commands on create.
* *
@ -244,7 +257,12 @@ public void execute(EnumSet<TargetType> targetTypes, Action action, Metadata met
LOG.runningHbm2ddlSchemaExport(); LOG.runningHbm2ddlSchemaExport();
final TargetDescriptor targetDescriptor = buildTargetDescriptor( targetTypes, outputFile, serviceRegistry ); final TargetDescriptor targetDescriptor = buildTargetDescriptor(
targetTypes,
outputFile,
append,
serviceRegistry
);
doExecution( action, needsJdbcConnection( targetTypes ), metadata, serviceRegistry, targetDescriptor ); doExecution( action, needsJdbcConnection( targetTypes ), metadata, serviceRegistry, targetDescriptor );
} }
@ -316,6 +334,14 @@ public static TargetDescriptor buildTargetDescriptor(
EnumSet<TargetType> targetTypes, EnumSet<TargetType> targetTypes,
String outputFile, String outputFile,
ServiceRegistry serviceRegistry) { ServiceRegistry serviceRegistry) {
return buildTargetDescriptor( targetTypes, outputFile, true, serviceRegistry );
}
public static TargetDescriptor buildTargetDescriptor(
EnumSet<TargetType> targetTypes,
String outputFile,
boolean append,
ServiceRegistry serviceRegistry) {
final ScriptTargetOutput scriptTarget; final ScriptTargetOutput scriptTarget;
if ( targetTypes.contains( TargetType.SCRIPT ) ) { if ( targetTypes.contains( TargetType.SCRIPT ) ) {
if ( outputFile == null ) { if ( outputFile == null ) {
@ -324,7 +350,8 @@ public static TargetDescriptor buildTargetDescriptor(
scriptTarget = Helper.interpretScriptTargetSetting( scriptTarget = Helper.interpretScriptTargetSetting(
outputFile, outputFile,
serviceRegistry.getService( ClassLoaderService.class ), serviceRegistry.getService( ClassLoaderService.class ),
(String) serviceRegistry.getService( ConfigurationService.class ).getSettings().get( AvailableSettings.HBM2DDL_CHARSET_NAME ) (String) serviceRegistry.getService( ConfigurationService.class ).getSettings().get( AvailableSettings.HBM2DDL_CHARSET_NAME ),
append
); );
} }
else { else {

View File

@ -55,6 +55,7 @@ public class SchemaUpdate {
boolean haltOnError = false; boolean haltOnError = false;
private String outputFile; private String outputFile;
private boolean append = true;
private String delimiter; private String delimiter;
private boolean format; private boolean format;
@ -87,7 +88,7 @@ public void execute(EnumSet<TargetType> targetTypes, Metadata metadata, ServiceR
exceptionHandler exceptionHandler
); );
final TargetDescriptor targetDescriptor = SchemaExport.buildTargetDescriptor( targetTypes, outputFile, serviceRegistry ); final TargetDescriptor targetDescriptor = SchemaExport.buildTargetDescriptor( targetTypes, outputFile, append, serviceRegistry );
try { try {
tool.getSchemaMigrator( config ).doMigration( metadata, executionOptions, targetDescriptor ); tool.getSchemaMigrator( config ).doMigration( metadata, executionOptions, targetDescriptor );
@ -123,6 +124,18 @@ public SchemaUpdate setOutputFile(String outputFile) {
return this; return this;
} }
/**
* For generating a export script file, by default the content will be appended at the begin or end of the file.
*
* The sql will be written at the beginning of the file rather append to the end.
*
* @return this
*/
public SchemaUpdate setOverrideOutputFileContent() {
append = false;
return this;
}
/** /**
* Set the end of statement delimiter * Set the end of statement delimiter
* *

View File

@ -93,7 +93,8 @@ private static ScriptSourceInput interpretScriptSourceSetting(
public static ScriptTargetOutput interpretScriptTargetSetting( public static ScriptTargetOutput interpretScriptTargetSetting(
Object scriptTargetSetting, Object scriptTargetSetting,
ClassLoaderService classLoaderService, ClassLoaderService classLoaderService,
String charsetName ) { String charsetName,
boolean append) {
if ( scriptTargetSetting == null ) { if ( scriptTargetSetting == null ) {
return null; return null;
} }
@ -118,7 +119,7 @@ else if ( Writer.class.isInstance( scriptTargetSetting ) ) {
// assume it is a File path // assume it is a File path
final File file = new File( scriptTargetSettingString ); final File file = new File( scriptTargetSettingString );
return new ScriptTargetOutputToFile( file, charsetName ); return new ScriptTargetOutputToFile( file, charsetName, append );
} }
} }

View File

@ -28,6 +28,7 @@ public class ScriptTargetOutputToFile extends AbstractScriptTargetOutput impleme
private final File file; private final File file;
private final String charsetName; private final String charsetName;
private final boolean append;
private Writer writer; private Writer writer;
@ -36,10 +37,24 @@ public class ScriptTargetOutputToFile extends AbstractScriptTargetOutput impleme
* *
* @param file The file to read from * @param file The file to read from
* @param charsetName The charset name * @param charsetName The charset name
* @param append If true, then bytes will be written to the end of the file rather than the beginning
*/ */
public ScriptTargetOutputToFile(File file, String charsetName) { public ScriptTargetOutputToFile(File file, String charsetName, boolean append) {
this.file = file; this.file = file;
this.charsetName = charsetName; this.charsetName = charsetName;
this.append = append;
}
/**
* Constructs a ScriptTargetOutputToFile instance,
* the bytes will be written to the end of the file rather than the beginning
*
* @param file The file to read from
* @param charsetName The charset name
*
*/
public ScriptTargetOutputToFile(File file, String charsetName ) {
this(file, charsetName, true);
} }
@Override @Override
@ -53,7 +68,7 @@ protected Writer writer() {
@Override @Override
public void prepare() { public void prepare() {
super.prepare(); super.prepare();
this.writer = toFileWriter( this.file, this.charsetName ); this.writer = toFileWriter( this.file, this.charsetName, append );
} }
@Override @Override
@ -63,7 +78,7 @@ public void release() {
writer.close(); writer.close();
} }
catch (IOException e) { catch (IOException e) {
throw new SchemaManagementException( "Unable to close file writer : " + e.toString() ); throw new SchemaManagementException( "Unable to close file writer : " + e );
} }
finally { finally {
writer = null; writer = null;
@ -72,7 +87,7 @@ public void release() {
} }
@SuppressWarnings("ResultOfMethodCallIgnored") @SuppressWarnings("ResultOfMethodCallIgnored")
static Writer toFileWriter( File file, String charsetName ) { static Writer toFileWriter(File file, String charsetName, boolean append) {
try { try {
if ( ! file.exists() ) { if ( ! file.exists() ) {
// best effort, since this is very likely not allowed in EE environments // best effort, since this is very likely not allowed in EE environments
@ -84,17 +99,17 @@ static Writer toFileWriter( File file, String charsetName ) {
} }
} }
catch (Exception e) { catch (Exception e) {
log.debug( "Exception calling File#createNewFile : " + e.toString() ); log.debug( "Exception calling File#createNewFile : " + e );
} }
try { try {
return charsetName != null ? return charsetName != null ?
new OutputStreamWriter( new OutputStreamWriter(
new FileOutputStream( file, true ), new FileOutputStream( file, append ),
charsetName charsetName
) : ) :
new OutputStreamWriter( new FileOutputStream( new OutputStreamWriter( new FileOutputStream(
file, file,
true append
) ); ) );
} }
catch (IOException e) { catch (IOException e) {

View File

@ -28,6 +28,7 @@ public class ScriptTargetOutputToUrl extends AbstractScriptTargetOutput implemen
private final URL url; private final URL url;
private final String charsetName; private final String charsetName;
private final boolean append;
private Writer writer; private Writer writer;
@ -36,10 +37,23 @@ public class ScriptTargetOutputToUrl extends AbstractScriptTargetOutput implemen
* *
* @param url The url to read from * @param url The url to read from
* @param charsetName The charset name * @param charsetName The charset name
* @param append If true, then bytes will be written to the end of the file rather than the beginning
*/ */
public ScriptTargetOutputToUrl(URL url, String charsetName) { public ScriptTargetOutputToUrl(URL url, String charsetName, boolean append) {
this.url = url; this.url = url;
this.charsetName = charsetName; this.charsetName = charsetName;
this.append = append;
}
/**
* Constructs a ScriptTargetOutputToUrl instance
* the bytes will be written to the end of the file rather than the beginning
*
* @param url The url to read from
* @param charsetName The charset name
*/
public ScriptTargetOutputToUrl(URL url, String charsetName) {
this( url, charsetName, true );
} }
@Override @Override
@ -53,7 +67,7 @@ protected Writer writer() {
@Override @Override
public void prepare() { public void prepare() {
super.prepare(); super.prepare();
this.writer = toWriter( url, charsetName ); this.writer = toWriter( url, charsetName, append );
} }
@Override @Override
@ -62,17 +76,17 @@ public void release() {
writer().close(); writer().close();
} }
catch (IOException e) { catch (IOException e) {
throw new SchemaManagementException( "Unable to close file writer : " + e.toString() ); throw new SchemaManagementException( "Unable to close file writer : " + e );
} }
} }
private static Writer toWriter( URL url, String charsetName ) { private static Writer toWriter( URL url, String charsetName, boolean append ) {
log.debug( "Attempting to resolve writer for URL : " + url ); log.debug( "Attempting to resolve writer for URL : " + url );
// technically only "strings corresponding to file URLs" are supported, which I take to mean URLs whose // technically only "strings corresponding to file URLs" are supported, which I take to mean URLs whose
// protocol is "file" // protocol is "file"
try { try {
return ScriptTargetOutputToFile.toFileWriter( new File( url.toURI() ), charsetName ); return ScriptTargetOutputToFile.toFileWriter( new File( url.toURI() ), charsetName, append );
} }
catch (URISyntaxException e) { catch (URISyntaxException e) {
throw new SchemaManagementException( throw new SchemaManagementException(

View File

@ -77,7 +77,7 @@ public static void process(
ExceptionHandlerLoggedImpl.INSTANCE ExceptionHandlerLoggedImpl.INSTANCE
); );
performScriptAction( actions.getScriptAction(), metadata, tool, serviceRegistry, executionOptions ); performScriptAction( actions.getScriptAction(), metadata, tool, serviceRegistry, executionOptions, configService );
performDatabaseAction( actions.getDatabaseAction(), metadata, tool, serviceRegistry, executionOptions ); performDatabaseAction( actions.getDatabaseAction(), metadata, tool, serviceRegistry, executionOptions );
if ( actions.getDatabaseAction() == Action.CREATE_DROP ) { if ( actions.getDatabaseAction() == Action.CREATE_DROP ) {
@ -260,13 +260,15 @@ private static void performScriptAction(
Metadata metadata, Metadata metadata,
SchemaManagementTool tool, SchemaManagementTool tool,
ServiceRegistry serviceRegistry, ServiceRegistry serviceRegistry,
ExecutionOptions executionOptions) { ExecutionOptions executionOptions,
ConfigurationService configurationService) {
switch ( scriptAction ) { switch ( scriptAction ) {
case CREATE_ONLY: { case CREATE_ONLY: {
final JpaTargetAndSourceDescriptor createDescriptor = buildScriptTargetDescriptor( final JpaTargetAndSourceDescriptor createDescriptor = buildScriptTargetDescriptor(
executionOptions.getConfigurationValues(), executionOptions.getConfigurationValues(),
CreateSettingSelector.INSTANCE, CreateSettingSelector.INSTANCE,
serviceRegistry serviceRegistry,
configurationService
); );
tool.getSchemaCreator( executionOptions.getConfigurationValues() ).doCreation( tool.getSchemaCreator( executionOptions.getConfigurationValues() ).doCreation(
metadata, metadata,
@ -281,7 +283,8 @@ private static void performScriptAction(
final JpaTargetAndSourceDescriptor dropDescriptor = buildScriptTargetDescriptor( final JpaTargetAndSourceDescriptor dropDescriptor = buildScriptTargetDescriptor(
executionOptions.getConfigurationValues(), executionOptions.getConfigurationValues(),
DropSettingSelector.INSTANCE, DropSettingSelector.INSTANCE,
serviceRegistry serviceRegistry,
configurationService
); );
tool.getSchemaDropper( executionOptions.getConfigurationValues() ).doDrop( tool.getSchemaDropper( executionOptions.getConfigurationValues() ).doDrop(
metadata, metadata,
@ -292,7 +295,8 @@ private static void performScriptAction(
final JpaTargetAndSourceDescriptor createDescriptor = buildScriptTargetDescriptor( final JpaTargetAndSourceDescriptor createDescriptor = buildScriptTargetDescriptor(
executionOptions.getConfigurationValues(), executionOptions.getConfigurationValues(),
CreateSettingSelector.INSTANCE, CreateSettingSelector.INSTANCE,
serviceRegistry serviceRegistry,
configurationService
); );
tool.getSchemaCreator( executionOptions.getConfigurationValues() ).doCreation( tool.getSchemaCreator( executionOptions.getConfigurationValues() ).doCreation(
metadata, metadata,
@ -306,7 +310,8 @@ private static void performScriptAction(
final JpaTargetAndSourceDescriptor dropDescriptor = buildScriptTargetDescriptor( final JpaTargetAndSourceDescriptor dropDescriptor = buildScriptTargetDescriptor(
executionOptions.getConfigurationValues(), executionOptions.getConfigurationValues(),
DropSettingSelector.INSTANCE, DropSettingSelector.INSTANCE,
serviceRegistry serviceRegistry,
configurationService
); );
tool.getSchemaDropper( executionOptions.getConfigurationValues() ).doDrop( tool.getSchemaDropper( executionOptions.getConfigurationValues() ).doDrop(
metadata, metadata,
@ -320,7 +325,8 @@ private static void performScriptAction(
final JpaTargetAndSourceDescriptor migrateDescriptor = buildScriptTargetDescriptor( final JpaTargetAndSourceDescriptor migrateDescriptor = buildScriptTargetDescriptor(
executionOptions.getConfigurationValues(), executionOptions.getConfigurationValues(),
MigrateSettingSelector.INSTANCE, MigrateSettingSelector.INSTANCE,
serviceRegistry serviceRegistry,
configurationService
); );
tool.getSchemaMigrator( executionOptions.getConfigurationValues() ).doMigration( tool.getSchemaMigrator( executionOptions.getConfigurationValues() ).doMigration(
metadata, metadata,
@ -338,7 +344,8 @@ private static void performScriptAction(
private static JpaTargetAndSourceDescriptor buildScriptTargetDescriptor( private static JpaTargetAndSourceDescriptor buildScriptTargetDescriptor(
Map configurationValues, Map configurationValues,
SettingSelector settingSelector, SettingSelector settingSelector,
ServiceRegistry serviceRegistry) { ServiceRegistry serviceRegistry,
ConfigurationService configurationService) {
final Object scriptSourceSetting = settingSelector.getScriptSourceSetting( configurationValues ); final Object scriptSourceSetting = settingSelector.getScriptSourceSetting( configurationValues );
final SourceType sourceType = SourceType.interpret( final SourceType sourceType = SourceType.interpret(
settingSelector.getSourceTypeSetting( configurationValues ), settingSelector.getSourceTypeSetting( configurationValues ),
@ -358,10 +365,13 @@ private static JpaTargetAndSourceDescriptor buildScriptTargetDescriptor(
? Helper.interpretScriptSourceSetting( scriptSourceSetting, serviceRegistry.getService( ClassLoaderService.class ), charsetName ) ? Helper.interpretScriptSourceSetting( scriptSourceSetting, serviceRegistry.getService( ClassLoaderService.class ), charsetName )
: null; : null;
boolean append = configurationService.getSetting( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_APPEND, StandardConverters.BOOLEAN, true );
final ScriptTargetOutput scriptTargetOutput = Helper.interpretScriptTargetSetting( final ScriptTargetOutput scriptTargetOutput = Helper.interpretScriptTargetSetting(
settingSelector.getScriptTargetSetting( configurationValues ), settingSelector.getScriptTargetSetting( configurationValues ),
serviceRegistry.getService( ClassLoaderService.class ), serviceRegistry.getService( ClassLoaderService.class ),
charsetName charsetName,
append
); );
return new JpaTargetAndSourceDescriptor() { return new JpaTargetAndSourceDescriptor() {