Skip to content

Commit 655171e

Browse files
committed
HHH-19931 add SchemaManager.truncateTable()
1 parent c3e819f commit 655171e

File tree

6 files changed

+169
-25
lines changed

6 files changed

+169
-25
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/relational/QualifiedNameParser.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,19 @@ public boolean equals(Object o) {
7979
if ( this == o ) {
8080
return true;
8181
}
82-
if ( !(o instanceof NameParts that) ) {
82+
else if ( !(o instanceof NameParts that) ) {
8383
return false;
8484
}
85-
return Objects.equals( this.catalogName, that.catalogName )
86-
&& Objects.equals( this.schemaName, that.schemaName )
87-
&& Objects.equals( this.objectName, that.objectName );
85+
else {
86+
return Objects.equals( this.catalogName, that.catalogName )
87+
&& Objects.equals( this.schemaName, that.schemaName )
88+
&& Objects.equals( this.objectName, that.objectName );
89+
}
8890
}
8991

9092
@Override
9193
public int hashCode() {
92-
return Objects.hash( catalogName, schemaName, objectName );
94+
return Objects.hash( catalogName, schemaName, objectName );
9395
}
9496
}
9597

hibernate-core/src/main/java/org/hibernate/relational/SchemaManager.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,33 @@ public interface SchemaManager extends jakarta.persistence.SchemaManager {
7777
* Programmatic way to run {@link org.hibernate.tool.schema.spi.SchemaTruncator}.
7878
* <p>
7979
* This operation does not affect the {@linkplain org.hibernate.Cache second-level cache}.
80-
* Therefore, after calling {@code truncate()}, it might be necessary to also call
81-
* {@link org.hibernate.Cache#evictAllRegions} to clean up data held in the second-level
82-
* cache.
80+
* Therefore, after calling {@code truncateMappedObjects()}, it might be necessary to
81+
* also call {@link org.hibernate.Cache#evictAllRegions} to clean up data held in the
82+
* second-level cache.
8383
*
8484
* @apiNote This operation is a synonym for {@link #truncate}.
8585
*/
8686
void truncateMappedObjects();
8787

88+
/**
89+
* Truncate the given database table, and reset any associated
90+
* {@linkplain jakarta.persistence.SequenceGenerator sequence} or table backing a
91+
* {@linkplain jakarta.persistence.TableGenerator table generator}.
92+
* Do not repopulate the table.
93+
* <p>
94+
* This operation does not affect the {@linkplain org.hibernate.Cache second-level cache}.
95+
* Therefore, after calling {@code truncate()}, it might be necessary to also call
96+
* {@link org.hibernate.Cache#evictRegion(String)} to clean up data held in the
97+
* second-level cache.
98+
*
99+
* @param tableName The name of the table to truncate, which must be a table mapped by
100+
* some entity class or collection
101+
*
102+
* @since 7.2
103+
*/
104+
@Incubating
105+
void truncateTable(String tableName);
106+
88107
/**
89108
* Populate the database by executing {@code /import.sql} and any other configured
90109
* {@linkplain org.hibernate.cfg.AvailableSettings#JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE

hibernate-core/src/main/java/org/hibernate/relational/internal/SchemaManagerImpl.java

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
*/
55
package org.hibernate.relational.internal;
66

7+
import org.hibernate.boot.model.relational.Namespace;
8+
import org.hibernate.boot.model.relational.Sequence;
79
import org.hibernate.boot.spi.MetadataImplementor;
810
import org.hibernate.engine.spi.SessionFactoryImplementor;
11+
import org.hibernate.mapping.Table;
912
import org.hibernate.relational.SchemaManager;
1013
import org.hibernate.tool.schema.Action;
14+
import org.hibernate.tool.schema.spi.SchemaFilter;
15+
import org.hibernate.tool.schema.spi.SchemaFilterProvider;
1116
import org.hibernate.tool.schema.spi.SchemaManagementException;
1217
import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator;
1318

@@ -18,9 +23,14 @@
1823

1924
import static org.hibernate.cfg.MappingSettings.DEFAULT_CATALOG;
2025
import static org.hibernate.cfg.MappingSettings.DEFAULT_SCHEMA;
26+
import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_IMPORT_FILES;
27+
import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_LOAD_SCRIPT_SOURCE;
28+
import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_SKIP_DEFAULT_IMPORT_FILE;
2129
import static org.hibernate.cfg.SchemaToolingSettings.JAKARTA_HBM2DDL_CREATE_SCHEMAS;
2230
import static org.hibernate.cfg.SchemaToolingSettings.JAKARTA_HBM2DDL_DATABASE_ACTION;
31+
import static org.hibernate.cfg.SchemaToolingSettings.JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE;
2332
import static org.hibernate.cfg.SchemaToolingSettings.JAKARTA_HBM2DDL_SCRIPTS_ACTION;
33+
import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_FILTER_PROVIDER;
2434

2535
/**
2636
* Implementation of {@link SchemaManager}, backed by a {@link SessionFactoryImplementor}
@@ -128,6 +138,65 @@ public void truncateMappedObjects() {
128138
);
129139
}
130140

141+
@Override
142+
public void truncateTable(String tableName) {
143+
Map<String, Object> properties = new HashMap<>( sessionFactory.getProperties() );
144+
properties.put( JAKARTA_HBM2DDL_DATABASE_ACTION, Action.TRUNCATE );
145+
properties.put( JAKARTA_HBM2DDL_SCRIPTS_ACTION, Action.NONE );
146+
properties.put( HBM2DDL_SKIP_DEFAULT_IMPORT_FILE, true );
147+
properties.remove( JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE );
148+
properties.remove( HBM2DDL_LOAD_SCRIPT_SOURCE );
149+
properties.remove( HBM2DDL_IMPORT_FILES );
150+
properties.put( HBM2DDL_FILTER_PROVIDER, new SchemaFilterProvider() {
151+
@Override
152+
public SchemaFilter getCreateFilter() {
153+
throw new UnsupportedOperationException();
154+
}
155+
156+
@Override
157+
public SchemaFilter getDropFilter() {
158+
throw new UnsupportedOperationException();
159+
}
160+
161+
@Override
162+
public SchemaFilter getTruncatorFilter() {
163+
return new SchemaFilter() {
164+
@Override
165+
public boolean includeNamespace(Namespace namespace) {
166+
return true;
167+
}
168+
169+
@Override
170+
public boolean includeTable(Table table) {
171+
return table.getName().equals( tableName );
172+
}
173+
174+
@Override
175+
public boolean includeSequence(Sequence sequence) {
176+
return false;
177+
}
178+
};
179+
}
180+
181+
@Override
182+
public SchemaFilter getMigrateFilter() {
183+
throw new UnsupportedOperationException();
184+
}
185+
186+
@Override
187+
public SchemaFilter getValidateFilter() {
188+
throw new UnsupportedOperationException();
189+
}
190+
} );
191+
addSchemaAndCatalog( properties );
192+
SchemaManagementToolCoordinator.process(
193+
metadata,
194+
sessionFactory.getServiceRegistry(),
195+
properties,
196+
action -> {}
197+
);
198+
}
199+
131200
@Override
132201
public void populate() {
133202
Map<String, Object> properties = new HashMap<>( sessionFactory.getProperties() );

hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaPopulator.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@ private void applyImportFiles(
142142
final String[] importFiles =
143143
StringHelper.split( ",",
144144
getString( HBM2DDL_IMPORT_FILES, options.getConfigurationValues(), defaultImportFile ) );
145+
if ( importFiles.length > 0 ) {
146+
applyImportFiles( options, commandExtractor, dialect, formatter, importFiles, targets );
147+
}
148+
}
149+
150+
private void applyImportFiles(
151+
ExecutionOptions options,
152+
SqlScriptCommandExtractor commandExtractor,
153+
Dialect dialect,
154+
Formatter formatter,
155+
String[] importFiles,
156+
GenerationTarget[] targets) {
145157
final String charsetName = getCharsetName( options );
146158
final var classLoaderService = getClassLoaderService();
147159
for ( String currentFile : importFiles ) {

hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaFilter.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.hibernate.boot.model.relational.Namespace;
99
import org.hibernate.boot.model.relational.Sequence;
1010
import org.hibernate.mapping.Table;
11+
import org.hibernate.tool.schema.internal.DefaultSchemaFilter;
1112

1213
/**
1314
* Defines a filter for Hibernate's schema tooling.
@@ -52,21 +53,5 @@ public interface SchemaFilter {
5253
/**
5354
* Matches everything
5455
*/
55-
SchemaFilter ALL = new SchemaFilter() {
56-
@Override
57-
public boolean includeNamespace( Namespace namespace ) {
58-
return true;
59-
}
60-
61-
@Override
62-
public boolean includeTable( Table table ) {
63-
return true;
64-
}
65-
66-
@Override
67-
public boolean includeSequence( Sequence sequence ) {
68-
return true;
69-
}
70-
};
71-
56+
SchemaFilter ALL = DefaultSchemaFilter.INSTANCE;
7257
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.schemamanager;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.GeneratedValue;
9+
import jakarta.persistence.Id;
10+
import jakarta.persistence.ManyToOne;
11+
import jakarta.persistence.Table;
12+
import org.hibernate.testing.orm.junit.DomainModel;
13+
import org.hibernate.testing.orm.junit.SessionFactory;
14+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
15+
import org.junit.jupiter.api.Test;
16+
17+
import static jakarta.persistence.GenerationType.SEQUENCE;
18+
import static org.junit.Assert.assertEquals;
19+
20+
@SessionFactory
21+
@DomainModel(annotatedClasses = TruncateTableTest.Trunk.class)
22+
class TruncateTableTest {
23+
@Test
24+
void test(SessionFactoryScope scope) {
25+
scope.inTransaction( session -> {
26+
Trunk trunk = new Trunk();
27+
session.persist( trunk );
28+
session.persist( new Trunk(trunk) );
29+
session.persist( new Trunk(trunk) );
30+
assertEquals( 1, trunk.id );
31+
} );
32+
scope.getSessionFactory().getSchemaManager()
33+
.truncateTable("trunk");
34+
scope.inTransaction( session -> {
35+
assertEquals(0,
36+
session.createQuery( "from Trunk", Trunk.class )
37+
.getResultCount());
38+
} );
39+
scope.inTransaction( session -> {
40+
Trunk trunk = new Trunk();
41+
session.persist( trunk );
42+
assertEquals( 1, trunk.id );
43+
} );
44+
}
45+
@Entity(name = "Trunk")
46+
@Table(name = "trunk")
47+
static class Trunk {
48+
@GeneratedValue(strategy = SEQUENCE) @Id
49+
long id;
50+
@ManyToOne Trunk parent;
51+
52+
Trunk() {}
53+
Trunk(Trunk parent) {
54+
this.parent = parent;
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)