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.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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <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
|
||||
* 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 "";
|
||||
}
|
||||
|
|
|
@ -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}.
|
||||
* <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 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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
* <ul>
|
||||
* <li>"Db2 UDB for z/OS", and
|
||||
* <li>"Db2 UDB for z/OS and OS/390".
|
||||
|
@ -208,4 +209,23 @@ public class DB2zDialect extends DB2Dialect {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 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 abstract class Dialect implements ConversionContext {
|
|||
* The name of a {@code rowid}-like pseudo-column which
|
||||
* acts as a high-performance row locator, or null if
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -859,7 +859,7 @@ public class H2Dialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String rowId() {
|
||||
public String rowId(String rowId) {
|
||||
return "_rowid_";
|
||||
}
|
||||
|
||||
|
|
|
@ -1408,7 +1408,7 @@ public class OracleDialect extends Dialect {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String rowId() {
|
||||
public String rowId(String rowId) {
|
||||
return "rowid";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -71,6 +71,12 @@ public class StandardTableExporter implements Exporter<Table> {
|
|||
}
|
||||
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() ) {
|
||||
createTable.append( ", " ).append( table.getPrimaryKey().sqlConstraintString( dialect ) );
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public class RowIdTest {
|
|||
void testRowId(SessionFactoryScope scope) {
|
||||
final String updatedName = "Smart phone";
|
||||
scope.inTransaction( session -> {
|
||||
String rowId = scope.getSessionFactory().getJdbcServices().getDialect().rowId();
|
||||
String rowId = scope.getSessionFactory().getJdbcServices().getDialect().rowId("");
|
||||
|
||||
SQLStatementInspector statementInspector = (SQLStatementInspector) scope.getStatementInspector();
|
||||
statementInspector.clear();
|
||||
|
|
|
@ -314,7 +314,7 @@ abstract public class DialectChecks {
|
|||
public static class SupportsRowId implements DialectCheck {
|
||||
@Override
|
||||
public boolean isMatch(Dialect dialect) {
|
||||
return dialect.rowId() != null;
|
||||
return dialect.rowId("") != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue