mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-17 00:24:57 +00:00
HHH-15958 support the @RowId annotation on DB2 LUW
... and perhaps also on DB2 for z and i (no way to test it)
This commit is contained in:
parent
366208924f
commit
76b2f92f39
@ -13,25 +13,35 @@
|
|||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies that an Oracle-style {@code rowid} should be used in SQL
|
* Specifies that a {@code rowid}-like column or pseudo-column should be
|
||||||
* {@code update} statements for an entity, instead of the primary key.
|
* used as the row locator in SQL {@code update} statements for an entity,
|
||||||
|
* instead of the primary key of the table.
|
||||||
* <p>
|
* <p>
|
||||||
* If the {@linkplain org.hibernate.dialect.Dialect SQL dialect} does
|
* 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
|
* @author Steve Ebersole
|
||||||
|
*
|
||||||
|
* @see org.hibernate.dialect.Dialect#rowId
|
||||||
*/
|
*/
|
||||||
@Target(TYPE)
|
@Target(TYPE)
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
public @interface RowId {
|
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.
|
||||||
* <p>
|
* <p>
|
||||||
* For example, on Oracle, this should be just {@code "rowid"}.
|
* It is <em>not</em> 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
|
* @apiNote Previously, this annotation member was required. But the
|
||||||
* automatically from the {@link org.hibernate.dialect.Dialect}
|
* 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 "";
|
String value() default "";
|
||||||
}
|
}
|
||||||
|
@ -948,8 +948,8 @@ public String generatedAs(String generatedAs) {
|
|||||||
@Override
|
@Override
|
||||||
public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData)
|
public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
builder.setAutoQuoteInitialUnderscore(true);
|
builder.setAutoQuoteInitialUnderscore( true );
|
||||||
return super.buildIdentifierHelper(builder, dbMetaData);
|
return super.buildIdentifierHelper( builder, dbMetaData );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -976,4 +976,20 @@ public String getTruncateTableStatement(String tableName) {
|
|||||||
public String getCreateUserDefinedTypeExtensionsString() {
|
public String getCreateUserDefinedTypeExtensionsString() {
|
||||||
return " instantiable mode db2sql";
|
return " instantiable mode db2sql";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The more "standard" syntax is {@code rid_bit(alias)} but here we use {@code alias.rowid}.
|
||||||
|
* <p>
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,10 @@
|
|||||||
|
|
||||||
import java.util.List;
|
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 Peter DeGregorio (pdegregorio)
|
||||||
* @author Christian Beikov
|
* @author Christian Beikov
|
||||||
@ -149,4 +151,23 @@ protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,11 @@
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hibernate.type.SqlTypes.ROWID;
|
||||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
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:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>"Db2 UDB for z/OS", and
|
* <li>"Db2 UDB for z/OS", and
|
||||||
* <li>"Db2 UDB for z/OS and OS/390".
|
* <li>"Db2 UDB for z/OS and OS/390".
|
||||||
@ -208,4 +209,23 @@ protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I speculate that this is a correct implementation of rowids for DB2 for z/OS,
|
||||||
|
// 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4628,8 +4628,17 @@ public SchemaManagementTool getFallbackSchemaManagementTool(
|
|||||||
* The name of a {@code rowid}-like pseudo-column which
|
* The name of a {@code rowid}-like pseudo-column which
|
||||||
* acts as a high-performance row locator, or null if
|
* acts as a high-performance row locator, or null if
|
||||||
* this dialect has no such pseudo-column.
|
* this dialect has no such pseudo-column.
|
||||||
|
* <p>
|
||||||
|
* 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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4642,4 +4651,15 @@ public String rowId() {
|
|||||||
public int rowIdSqlType() {
|
public int rowIdSqlType() {
|
||||||
return ROWID;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -859,7 +859,7 @@ public UniqueDelegate getUniqueDelegate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String rowId() {
|
public String rowId(String rowId) {
|
||||||
return "_rowid_";
|
return "_rowid_";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1408,7 +1408,7 @@ public String getCreateUserDefinedTypeKindString() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String rowId() {
|
public String rowId(String rowId) {
|
||||||
return "rowid";
|
return "rowid";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1350,7 +1350,7 @@ public boolean canBatchTruncate() {
|
|||||||
// (these would help if we used 'delete' instead of 'truncate')
|
// (these would help if we used 'delete' instead of 'truncate')
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String rowId() {
|
public String rowId(String rowId) {
|
||||||
return "ctid";
|
return "ctid";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
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.spi.StandardSqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.ast.tree.Statement;
|
import org.hibernate.sql.ast.tree.Statement;
|
||||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||||
|
@ -545,12 +545,7 @@ public AbstractEntityPersister(
|
|||||||
identifierAliases = new String[identifierColumnSpan];
|
identifierAliases = new String[identifierColumnSpan];
|
||||||
|
|
||||||
final String rowId = persistentClass.getRootTable().getRowId();
|
final String rowId = persistentClass.getRootTable().getRowId();
|
||||||
if ( rowId == null ) {
|
rowIdName = rowId == null ? null : dialect.rowId( rowId );
|
||||||
rowIdName = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rowIdName = rowId.isEmpty() ? dialect.rowId() : rowId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( persistentClass.getLoaderName() != null ) {
|
if ( persistentClass.getLoaderName() != null ) {
|
||||||
// We must resolve the named query on-demand through the boot model because it isn't initialized yet
|
// We must resolve the named query on-demand through the boot model because it isn't initialized yet
|
||||||
|
@ -71,6 +71,12 @@ public String[] getSqlCreateStrings(
|
|||||||
}
|
}
|
||||||
appendColumn( createTable, column, table, metadata, dialect, context );
|
appendColumn( createTable, column, table, metadata, dialect, context );
|
||||||
}
|
}
|
||||||
|
if ( table.getRowId() != null ) {
|
||||||
|
String rowIdColumn = dialect.getRowIdColumnString( table.getRowId() );
|
||||||
|
if ( rowIdColumn != null ) {
|
||||||
|
createTable.append(", ").append( rowIdColumn );
|
||||||
|
}
|
||||||
|
}
|
||||||
if ( table.hasPrimaryKey() ) {
|
if ( table.hasPrimaryKey() ) {
|
||||||
createTable.append( ", " ).append( table.getPrimaryKey().sqlConstraintString( dialect ) );
|
createTable.append( ", " ).append( table.getPrimaryKey().sqlConstraintString( dialect ) );
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ void setUp(SessionFactoryScope scope) {
|
|||||||
void testRowId(SessionFactoryScope scope) {
|
void testRowId(SessionFactoryScope scope) {
|
||||||
final String updatedName = "Smart phone";
|
final String updatedName = "Smart phone";
|
||||||
scope.inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
String rowId = scope.getSessionFactory().getJdbcServices().getDialect().rowId();
|
String rowId = scope.getSessionFactory().getJdbcServices().getDialect().rowId("");
|
||||||
|
|
||||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||||
statementInspector.clear();
|
statementInspector.clear();
|
||||||
|
@ -314,7 +314,7 @@ public boolean isMatch(Dialect dialect) {
|
|||||||
public static class SupportsRowId implements DialectCheck {
|
public static class SupportsRowId implements DialectCheck {
|
||||||
@Override
|
@Override
|
||||||
public boolean isMatch(Dialect dialect) {
|
public boolean isMatch(Dialect dialect) {
|
||||||
return dialect.rowId() != null;
|
return dialect.rowId("") != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user