diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/RowId.java b/hibernate-core/src/main/java/org/hibernate/annotations/RowId.java index bbbcfb6389..3fd7a9fbb1 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/RowId.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/RowId.java @@ -13,25 +13,35 @@ import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * Specifies that an Oracle-style {@code rowid} should be used in SQL - * {@code update} statements for an entity, instead of the primary key. + * Specifies that a {@code rowid}-like column or pseudo-column should be + * used as the row locator in SQL {@code update} statements for an entity, + * instead of the primary key of the table. *
* If the {@linkplain org.hibernate.dialect.Dialect SQL dialect} does - * not support some sort of {@code rowid}, this annotation is ignored. + * not support some sort of {@code rowid}-like column or pseudo-column, + * then this annotation is ignored, and the primary key is used as the + * row locator. * * @author Steve Ebersole + * + * @see org.hibernate.dialect.Dialect#rowId */ @Target(TYPE) @Retention(RUNTIME) public @interface RowId { /** - * Specifies the {@code rowid} identifier. + * Specifies the name of the {@code rowid}-like column for databases + * where the column is declared explicitly in DDL. *
- * For example, on Oracle, this should be just {@code "rowid"}. + * It is not necessary to specify the name for databases where + * the {@code rowid}-like value is an implicitly-existing pseudo-column, + * and on those databases, this annotation member is ignored. * - * @deprecated the {@code rowid} identifier is now inferred - * automatically from the {@link org.hibernate.dialect.Dialect} + * @apiNote Previously, this annotation member was required. But the + * name of the column it is now usually determined by calling + * {@link org.hibernate.dialect.Dialect#rowId}, and so this + * member is now usually ignored. The exception is for certain + * flavors of DB2. */ - @Deprecated(since = "6.2") String value() default ""; } 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 939d711bc4..292f972241 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -948,8 +948,8 @@ public class DB2Dialect extends Dialect { @Override public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { - builder.setAutoQuoteInitialUnderscore(true); - return super.buildIdentifierHelper(builder, dbMetaData); + builder.setAutoQuoteInitialUnderscore( true ); + return super.buildIdentifierHelper( builder, dbMetaData ); } @Override @@ -976,4 +976,20 @@ public class DB2Dialect extends Dialect { public String getCreateUserDefinedTypeExtensionsString() { return " instantiable mode db2sql"; } + + /** + * The more "standard" syntax is {@code rid_bit(alias)} but here we use {@code alias.rowid}. + *
+ * There is also an alternative {@code rid()} of type {@code bigint}, but it cannot be used + * with partitioning. + */ + @Override + public String rowId(String rowId) { + return "rowid"; + } + + @Override + public int rowIdSqlType() { + return VARBINARY; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java index 4edb35dd89..8a8a791b14 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java @@ -28,8 +28,10 @@ import org.hibernate.sql.exec.spi.JdbcOperation; import java.util.List; +import static org.hibernate.type.SqlTypes.ROWID; + /** - * A SQL dialect for DB2 for iSeries version 7.1 and above, previously known as "DB2/400". + * A SQL dialect for DB2 for IBM i version 7.1 and above, previously known as "DB2/400". * * @author Peter DeGregorio (pdegregorio) * @author Christian Beikov @@ -149,4 +151,23 @@ public class DB2iDialect extends DB2Dialect { } }; } + + // I speculate that this is a correct implementation of rowids for DB2 for i, + // just on the basis of the DB2 docs, but I currently have no way to test it + // Note that the implementation inherited from DB2Dialect for LUW will not work! + + @Override + public String rowId(String rowId) { + return rowId.isEmpty() ? "rowid_" : rowId; + } + + @Override + public int rowIdSqlType() { + return ROWID; + } + + @Override + public String getRowIdColumnString(String rowId) { + return rowId( rowId ) + " rowid not null generated always"; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2zDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2zDialect.java index b275ef4db1..4f6874dbae 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2zDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2zDialect.java @@ -30,10 +30,11 @@ import jakarta.persistence.TemporalType; import java.util.List; +import static org.hibernate.type.SqlTypes.ROWID; import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE; /** - * A SQL dialect for DB2 for z/OS version 12.1 and above, previously known as : + * A SQL dialect for DB2 for z/OS version 12.1 and above, previously known as: *
+ * If the {@code rowid}-like value is an explicitly-declared + * named column instead of an implicit pseudo-column, and if + * the given name is nonempty, return the given name. + * + * @param rowId the name specified by + * {@link org.hibernate.annotations.RowId#value()}, + * which is ignored if {@link #getRowIdColumnString} + * is not overridden */ - public String rowId() { + public String rowId(String rowId) { return null; } @@ -4642,4 +4651,15 @@ public abstract class Dialect implements ConversionContext { public int rowIdSqlType() { return ROWID; } + + /** + * If this dialect requires that the {@code rowid} column be + * declared explicitly, return the DDL column definition. + * + * @return the DDL column definition, or {@code null} if + * the {@code rowid} is an implicit pseudo-column + */ + public String getRowIdColumnString(String rowId) { + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index 0ad061f097..ca63ff89db 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -859,7 +859,7 @@ public class H2Dialect extends Dialect { } @Override - public String rowId() { + public String rowId(String rowId) { return "_rowid_"; } 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 a47a663d2b..804d554958 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -1408,7 +1408,7 @@ public class OracleDialect extends Dialect { } @Override - public String rowId() { + public String rowId(String rowId) { return "rowid"; } } 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 63cd7183b1..2759f4414b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -1350,7 +1350,7 @@ public class PostgreSQLDialect extends Dialect { // (these would help if we used 'delete' instead of 'truncate') @Override - public String rowId() { + public String rowId(String rowId) { return "ctid"; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java index 2ee7facb86..87c91ff587 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TiDBDialect.java @@ -15,7 +15,6 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslatorFactory; -import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.exec.spi.JdbcOperation; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 69c1ab5461..4ab55aa784 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -545,12 +545,7 @@ public abstract class AbstractEntityPersister identifierAliases = new String[identifierColumnSpan]; final String rowId = persistentClass.getRootTable().getRowId(); - if ( rowId == null ) { - rowIdName = null; - } - else { - rowIdName = rowId.isEmpty() ? dialect.rowId() : rowId; - } + rowIdName = rowId == null ? null : dialect.rowId( rowId ); if ( persistentClass.getLoaderName() != null ) { // We must resolve the named query on-demand through the boot model because it isn't initialized yet diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java index 0b6f412eea..3326a6743a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java @@ -71,6 +71,12 @@ public class StandardTableExporter implements Exporter