finish off jdoc for DDLTypes

This commit is contained in:
Gavin 2022-11-14 12:18:50 +01:00 committed by Gavin King
parent 867b1146ab
commit 1d5f6b5c13
5 changed files with 122 additions and 25 deletions

View File

@ -24,8 +24,13 @@ import java.sql.Types;
* {@link org.hibernate.type.descriptor.java.JavaType#getRecommendedJdbcType},
* or when the {@link org.hibernate.annotations.JdbcTypeCode @JdbcTypeCode}
* annotation is used, for example.
* <p>
* A type code may also be used as a key to obtain a dialect-specific
* {@link org.hibernate.type.descriptor.sql.DdlType} for the purposes of
* generating DDL.
*
* @see org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry
* @see org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry
*
* @author Christian Beikov
*/

View File

@ -38,7 +38,7 @@ import org.hibernate.type.spi.TypeConfiguration;
public class ArrayJdbcType implements JdbcType {
public static final ArrayJdbcType INSTANCE = new ArrayJdbcType( ObjectJdbcType.INSTANCE );
private static final ClassValue<Method> NAME_BINDER = new ClassValue<Method>() {
private static final ClassValue<Method> NAME_BINDER = new ClassValue<>() {
@Override
protected Method computeValue(Class<?> type) {
try {
@ -137,7 +137,7 @@ public class ArrayJdbcType implements JdbcType {
throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex );
}
}
// Not that it's supposed to have setArray(String,Array) by standard.
// Note that it's supposed to have setArray(String,Array) by standard.
// There are numerous missing methods that only have versions for positional parameter,
// but not named ones.

View File

@ -7,18 +7,23 @@
package org.hibernate.type.descriptor.sql;
import java.io.Serializable;
import java.sql.Types;
import org.hibernate.Incubating;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SqlExpressible;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
/**
* Descriptor for a DDL type.
* Descriptor for a DDL column type. An instance of this type abstracts over
* a parameterized family of {@linkplain Dialect dialect-specific} SQL types
* with the same {@linkplain #getSqlTypeCode() type code} but varying length,
* precision, and scale. Usually, the types belonging to the family share a
* single {@linkplain #getRawTypeName() type name} in SQL, but in certain
* cases, most notably, in the case of the MySQL LOB types {@code text} and
* {@code blob}, it's the type name itself which is parameter-dependent.
*
* @author Christian Beikov
*/
@ -46,20 +51,46 @@ public interface DdlType extends Serializable {
String getTypeNamePattern();
/**
* Return a type with length, precision, and scale specified by the given
* {@linkplain Size size object}.
*/
default String getTypeName(Size size) {
return getTypeName( size.getLength(), size.getPrecision(), size.getScale() );
}
/**
* Return a type with the given length, precision, and scale.
*/
String getTypeName(Long size, Integer precision, Integer scale);
/**
* Return the database type corresponding to the given {@link JdbcType}
* that may be used as a target type in casting operations using the SQL
* {@code CAST()} function, using the given {@link JavaType} to help
* determine the appropriate precision and scale. The length is usually
* chosen to be the maximum possible length for the dialect.
*
* @see JavaType#getDefaultSqlScale(Dialect, JdbcType)
* @see JavaType#getDefaultSqlPrecision(Dialect, JdbcType)
* @see Dialect#getMaxVarcharLength()
*
* @return The SQL type name
*/
String getCastTypeName(JdbcType jdbcType, JavaType<?> javaType);
/**
* Get the name of the database type appropriate for casting operations
* (via the CAST() SQL function) for the given {@link SqlExpressible}
* SQL type.
* Return the database type with the given length, precision, and scale,
* if specified, corresponding to the {@link SqlExpressible#getJdbcMapping()
* JdbcMapping} of the given {@link SqlExpressible}, that may be used as a
* target type in casting operations using the SQL {@code CAST()} function.
*
* @return The database type name
* @param type the {@link SqlExpressible}
* @param length the length, or null, if unspecified
* @param precision the precision, or null, if unspecified
* @param scale the scale, or null, if unspecified
*
* @return The SQL type name
*/
default String getCastTypeName(SqlExpressible type, Long length, Integer precision, Integer scale) {
return getCastTypeName(
@ -71,5 +102,20 @@ public interface DdlType extends Serializable {
);
}
/**
* Return the database type with the given length, precision, and scale,
* if specified, corresponding to the given {@link JdbcType}, that may
* be used as a target type in casting operations using the SQL
* {@code CAST()} function, using the given {@link JavaType} to help
* determine the appropriate precision and scale. The length, if not
* explicitly specified, is usually chosen to be the maximum possible
* length for the dialect.
*
* @see JavaType#getDefaultSqlScale(Dialect, JdbcType)
* @see JavaType#getDefaultSqlPrecision(Dialect, JdbcType)
* @see Dialect#getMaxVarcharLength()
*
* @return The SQL type name
*/
String getCastTypeName(JdbcType jdbcType, JavaType<?> javaType, Long length, Integer precision, Integer scale);
}

View File

@ -23,7 +23,8 @@ import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
/**
* Basically a map from SQL type code (int) -> {@link DdlType}
* A registry mapping {@link org.hibernate.type.SqlTypes JDBC type codes}
* to instances of the {@link DdlType} interface.
*
* @author Christian Beikov
*
@ -42,10 +43,17 @@ public class DdlTypeRegistry implements Serializable {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// baseline descriptors
/**
* Add a mapping from the {@linkplain DdlType#getSqlTypeCode() type code}
* of the given {@link DdlType} to the given {@code DdlType}.
*/
public void addDescriptor(DdlType ddlType) {
addDescriptor( ddlType.getSqlTypeCode(), ddlType );
}
/**
* Add a mapping from the given type code to the given {@link DdlType}.
*/
public void addDescriptor(int sqlTypeCode, DdlType ddlType) {
final DdlType previous = ddlTypes.put( sqlTypeCode, ddlType );
if ( previous != null && previous != ddlType ) {
@ -57,16 +65,29 @@ public class DdlTypeRegistry implements Serializable {
addSqlType( ddlType, sqlTypeCode );
}
/**
* Add a mapping from the {@linkplain DdlType#getSqlTypeCode() type code}
* of the given {@link DdlType} to the given {@code DdlType}, if there
* is no mapping already present for that type code.
*/
public void addDescriptorIfAbsent(DdlType ddlType) {
addDescriptorIfAbsent( ddlType.getSqlTypeCode(), ddlType );
}
/**
* Add a mapping from the given type code to the given {@link DdlType},
* if there is no mapping already present for the given type code.
*/
public void addDescriptorIfAbsent(int sqlTypeCode, DdlType ddlType) {
if ( ddlTypes.putIfAbsent( sqlTypeCode, ddlType ) == null ) {
addSqlType( ddlType, sqlTypeCode );
}
}
/**
* Add a mapping from the given type code to the raw type name of the
* given {@link DdlType}.
*/
private void addSqlType(DdlType ddlType, int sqlTypeCode) {
for ( String rawTypeName : ddlType.getRawTypeNames() ) {
final Integer previousSqlTypeCode = sqlTypes.put( rawTypeName, sqlTypeCode );
@ -78,7 +99,8 @@ public class DdlTypeRegistry implements Serializable {
}
/**
* Returns the {@link SqlTypes} type code for the given DDL raw type name, or <code>null</code> if it is unknown.
* Returns the {@link SqlTypes} type code for the given DDL raw type name, or
* {@code null} if the type code cannot be determined from the registrations.
*/
public Integer getSqlTypeCode(String rawTypeName) {
return sqlTypes.get( rawTypeName );
@ -87,11 +109,11 @@ public class DdlTypeRegistry implements Serializable {
/**
* Returns the registered {@link DdlType} for the given SQL type code.
* <p>
* Not that the "long" types {@link Types#LONGVARCHAR}, {@link Types#LONGNVARCHAR}
* and {@link Types#LONGVARBINARY} are considered synonyms for their
* non-{@code LONG} counterparts, with the only difference being that
* a different default length is used: {@link org.hibernate.Length#LONG}
* instead of {@link org.hibernate.Length#DEFAULT}.
* Note that the "long" types {@link Types#LONGVARCHAR}, {@link Types#LONGNVARCHAR},
* and {@link Types#LONGVARBINARY} are considered synonyms for their non-{@code LONG}
* counterparts, with the only difference being that a different default length is
* used by default: {@link org.hibernate.Length#LONG} instead of
* {@link org.hibernate.Length#DEFAULT}.
*
*/
public DdlType getDescriptor(int sqlTypeCode) {
@ -113,6 +135,15 @@ public class DdlTypeRegistry implements Serializable {
return ddlType;
}
/**
* Get the SQL type name for the specified {@link java.sql.Types JDBC type code},
* filling in the placemarkers {@code $l}, {@code $p}, and {@code $s}
* with the default length, precision, and scale for the given SQL dialect.
*
* @param typeCode the JDBC type code
* @param dialect the dialect which determines the default length, precision, and scale
* @return a SQL column type
*/
public String getTypeName(int typeCode, Dialect dialect) {
// explicitly enforce dialect's default precisions
switch ( typeCode ) {
@ -133,6 +164,19 @@ public class DdlTypeRegistry implements Serializable {
}
}
/**
* Get the SQL type name for the specified {@link java.sql.Types JDBC type code}
* and size, filling in the placemarkers {@code $l}, {@code $p}, and {@code $s}
* with the length, precision, and scale determined by the given {@linkplain Size
* size object}. The returned type name should be of a SQL type large enough to
* accommodate values of the specified size.
*
* @param typeCode the JDBC type code
* @param size an object which determines the length, precision, and scale
*
* @return the associated type name with the smallest capacity that accommodates
* the given size, if available, and the default type name otherwise
*/
public String getTypeName(int typeCode, Size size) {
return getTypeName( typeCode, size.getLength(), size.getPrecision(), size.getScale() );
}
@ -140,15 +184,16 @@ public class DdlTypeRegistry implements Serializable {
/**
* Get the SQL type name for the specified {@link java.sql.Types JDBC type code}
* and size, filling in the placemarkers {@code $l}, {@code $p}, and {@code $s}
* with the given length, precision, and scale.
* with the given length, precision, and scale. The returned type name should be
* of a SQL type large enough to accommodate values of the specified size.
*
* @param typeCode the JDBC type code
* @param size the SQL length, if any
* @param precision the SQL precision, if any
* @param scale the SQL scale, if any
*
* @return the associated name with smallest capacity >= size, if available and
* the default type name otherwise
* @return the associated type name with the smallest capacity that accommodates
* the given size, if available, and the default type name otherwise
*/
public String getTypeName(int typeCode, Long size, Integer precision, Integer scale) {
final DdlType descriptor = getDescriptor( typeCode );
@ -165,12 +210,13 @@ public class DdlTypeRegistry implements Serializable {
}
/**
* Whether or not the given type name has been registered for this dialect (including both hibernate type names and
* custom-registered type names).
* Determines if there is a registered {@link DdlType} whose {@linkplain
* DdlType#getRawTypeName() raw type name} matches the given type name,
* taking into account DDL types registered by Hibernate.
*
* @param typeName the type name.
*
* @return true if the given string has been registered either as a hibernate type or as a custom-registered one
* @return {@code true} if there is a DDL type with the given raw type name
*/
public boolean isTypeNameRegistered(final String typeName) {
for ( DdlType value : ddlTypes.values() ) {

View File

@ -62,7 +62,7 @@ public class ParameterTest extends BaseEntityManagerFunctionalTestCase {
ParameterExpression<Integer[]> param = em.getCriteriaBuilder().parameter( Integer[].class, "theIntegers" );
criteria.where( em.getCriteriaBuilder().equal( thePath, param ) );
TypedQuery<MultiTypedBasicAttributesEntity> query = em.createQuery( criteria );
query.setParameter( param, new Integer[] { Integer.valueOf(1), Integer.valueOf(1), Integer.valueOf(1) } );
query.setParameter( param, new Integer[] {1, 1, 1} );
assertThat( query.getParameterValue( param.getName() ), instanceOf( Integer[].class ) );
query.getResultList();
em.getTransaction().commit();
@ -85,7 +85,7 @@ public class ParameterTest extends BaseEntityManagerFunctionalTestCase {
);
TypedQuery<MultiTypedBasicAttributesEntity> query = em.createQuery( criteria );
Parameter parameter = query.getParameter( "id" );
Parameter<?> parameter = query.getParameter( "id" );
assertEquals( "id", parameter.getName() );
em.getTransaction().commit();
@ -140,7 +140,7 @@ public class ParameterTest extends BaseEntityManagerFunctionalTestCase {
}
@Override
public Class[] getAnnotatedClasses() {
public Class<?>[] getAnnotatedClasses() {
return new Class[] { MultiTypedBasicAttributesEntity.class };
}
}