Implement type name preserving for envers and properly escape string values when transforming to literals

This commit is contained in:
Christian Beikov 2021-09-01 18:06:16 +02:00
parent acc5d0d977
commit f23ecfc58e
22 changed files with 144 additions and 55 deletions

View File

@ -0,0 +1,35 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.internal;
/**
* @author Christian Beikov
*/
public class QueryLiteralHelper {
private QueryLiteralHelper() {
// disallow direct instantiation
}
public static String toStringLiteral(String value) {
final StringBuilder sb = new StringBuilder( value.length() + 2 );
appendStringLiteral( sb, value );
return sb.toString();
}
public static void appendStringLiteral(StringBuilder sb, String value) {
sb.append( '\'' );
for ( int i = 0; i < value.length(); i++ ) {
final char c = value.charAt( i );
if ( c == '\'' ) {
sb.append( '\'' );
}
sb.append( c );
}
sb.append( '\'' );
}
}

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.query.sqm.tree.expression; package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.internal.QueryLiteralHelper;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmExpressable;
@ -54,15 +55,7 @@ public class SqmLiteral<T>
public static <T> void appendHqlString(StringBuilder sb, JavaTypeDescriptor<T> javaTypeDescriptor, T value) { public static <T> void appendHqlString(StringBuilder sb, JavaTypeDescriptor<T> javaTypeDescriptor, T value) {
final String string = javaTypeDescriptor.toString( value ); final String string = javaTypeDescriptor.toString( value );
if ( javaTypeDescriptor.getJavaTypeClass() == String.class ) { if ( javaTypeDescriptor.getJavaTypeClass() == String.class ) {
sb.append( '\'' ); QueryLiteralHelper.appendStringLiteral( sb, string );
for ( int i = 0; i < string.length(); i++ ) {
final char c = string.charAt( i );
if ( c == '\'' ) {
sb.append( '\'' );
}
sb.append( c );
}
sb.append( '\'' );
} }
else { else {
sb.append( string ); sb.append( string );

View File

@ -18,6 +18,7 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.internal.NamedStandardBasicTypeImpl;
import org.hibernate.type.internal.StandardBasicTypeImpl; import org.hibernate.type.internal.StandardBasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.UserType; import org.hibernate.usertype.UserType;
@ -75,6 +76,15 @@ public class BasicTypeRegistry implements Serializable {
); );
} }
public <J> BasicType<J> resolve(JavaTypeDescriptor<J> jtdToUse, JdbcTypeDescriptor stdToUse, String baseTypeName) {
//noinspection unchecked
return resolve(
jtdToUse,
stdToUse,
() -> new NamedStandardBasicTypeImpl<>( jtdToUse, stdToUse, baseTypeName )
);
}
/** /**
* Find an existing BasicType registration for the given JavaTypeDescriptor and * Find an existing BasicType registration for the given JavaTypeDescriptor and
* SqlTypeDescriptor combo or create (and register) one. * SqlTypeDescriptor combo or create (and register) one.

View File

@ -100,6 +100,6 @@ public class BinaryType
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry(); final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
final JdbcTypeDescriptor jdbcType = jdbcTypeRegistry.getDescriptor( Types.BLOB ); final JdbcTypeDescriptor jdbcType = jdbcTypeRegistry.getDescriptor( Types.BLOB );
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType ); return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType, getName() );
} }
} }

View File

@ -88,7 +88,7 @@ public class BooleanType
//noinspection unchecked //noinspection unchecked
return (BasicType<X>) indicators.getTypeConfiguration() return (BasicType<X>) indicators.getTypeConfiguration()
.getBasicTypeRegistry() .getBasicTypeRegistry()
.resolve( getJavaTypeDescriptor(), jdbcTypeDescriptor ); .resolve( getJavaTypeDescriptor(), jdbcTypeDescriptor, getName() );
} }
//noinspection unchecked //noinspection unchecked

View File

@ -57,6 +57,6 @@ public class CharArrayType
} }
final JdbcTypeDescriptor jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode ); final JdbcTypeDescriptor jdbcType = jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType ); return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType, getName() );
} }
} }

View File

@ -52,7 +52,8 @@ public class CharacterArrayClobType
return typeConfiguration.getBasicTypeRegistry().resolve( return typeConfiguration.getBasicTypeRegistry().resolve(
typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( domainJtd.getJavaType() ), typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( domainJtd.getJavaType() ),
jdbcType jdbcType,
getName()
); );
} }

View File

@ -50,7 +50,8 @@ public class CharacterArrayNClobType
return typeConfiguration.getBasicTypeRegistry().resolve( return typeConfiguration.getBasicTypeRegistry().resolve(
typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( domainJtd.getJavaType() ), typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( domainJtd.getJavaType() ),
jdbcType jdbcType,
getName()
); );
} }

View File

@ -59,7 +59,8 @@ public class CharacterArrayType
if ( domainJtd != null && domainJtd.getJavaTypeClass() == Character[].class ) { if ( domainJtd != null && domainJtd.getJavaTypeClass() == Character[].class ) {
return typeConfiguration.getBasicTypeRegistry().resolve( return typeConfiguration.getBasicTypeRegistry().resolve(
typeConfiguration.getJavaTypeDescriptorRegistry().resolveDescriptor( domainJtd.getJavaType() ), typeConfiguration.getJavaTypeDescriptorRegistry().resolveDescriptor( domainJtd.getJavaType() ),
indicatedJdbcType indicatedJdbcType,
getName()
); );
} }
@ -69,7 +70,8 @@ public class CharacterArrayType
return (BasicType<X>) typeConfiguration.getBasicTypeRegistry().resolve( return (BasicType<X>) typeConfiguration.getBasicTypeRegistry().resolve(
getJavaTypeDescriptor(), getJavaTypeDescriptor(),
indicatedJdbcType indicatedJdbcType,
getName()
); );
} }
} }

View File

@ -41,7 +41,13 @@ public class CharacterNCharType
} }
public String objectToSQLString(Character value, Dialect dialect) { public String objectToSQLString(Character value, Dialect dialect) {
return '\'' + toString( value ) + '\''; if ( value == '\'' ) {
return "''''";
}
final char[] chars = new char[3];
chars[0] = chars[2] = '\'';
chars[1] = value;
return new String( chars );
} }
public Character stringToObject(String xml) { public Character stringToObject(String xml) {

View File

@ -52,7 +52,13 @@ public class CharacterType
} }
public String objectToSQLString(Character value, Dialect dialect) { public String objectToSQLString(Character value, Dialect dialect) {
return '\'' + toString( value ) + '\''; if ( value == '\'' ) {
return "''''";
}
final char[] chars = new char[3];
chars[0] = chars[2] = '\'';
chars[1] = value;
return new String( chars );
} }
public Character stringToObject(String xml) { public Character stringToObject(String xml) {
@ -69,6 +75,6 @@ public class CharacterType
? jdbcTypeRegistry.getDescriptor( Types.NCHAR ) ? jdbcTypeRegistry.getDescriptor( Types.NCHAR )
: jdbcTypeRegistry.getDescriptor( Types.CHAR ); : jdbcTypeRegistry.getDescriptor( Types.CHAR );
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType ); return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcType, getName() );
} }
} }

View File

@ -58,7 +58,8 @@ public class ClobType extends AbstractSingleColumnStandardBasicType<Clob> implem
return typeConfiguration.getBasicTypeRegistry().resolve( return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd, domainJtd,
jdbcTypeRegistry.getDescriptor( Types.NCLOB ) jdbcTypeRegistry.getDescriptor( Types.NCLOB ),
getName()
); );
} }
} }

View File

@ -168,6 +168,7 @@ public class EnumType<T extends Enum<T>>
relationalJtd relationalJtd
); );
} }
this.jdbcTypeDescriptor = jdbcTypeDescriptor;
} }
else { else {
final String enumClassName = (String) parameters.get( ENUM ); final String enumClassName = (String) parameters.get( ENUM );
@ -180,9 +181,9 @@ public class EnumType<T extends Enum<T>>
this.enumValueConverter = interpretParameters( parameters ); this.enumValueConverter = interpretParameters( parameters );
this.jdbcTypeDescriptor = typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( enumValueConverter.getJdbcTypeCode() ); this.jdbcTypeDescriptor = typeConfiguration.getJdbcTypeDescriptorRegistry().getDescriptor( enumValueConverter.getJdbcTypeCode() );
this.jdbcValueExtractor = (ValueExtractor) jdbcTypeDescriptor.getExtractor( enumValueConverter.getRelationalJavaDescriptor() );
this.jdbcValueBinder = (ValueBinder) jdbcTypeDescriptor.getBinder( enumValueConverter.getRelationalJavaDescriptor() );
} }
this.jdbcValueExtractor = (ValueExtractor) jdbcTypeDescriptor.getExtractor( enumValueConverter.getRelationalJavaDescriptor() );
this.jdbcValueBinder = (ValueBinder) jdbcTypeDescriptor.getBinder( enumValueConverter.getRelationalJavaDescriptor() );
if ( LOG.isDebugEnabled() ) { if ( LOG.isDebugEnabled() ) {
LOG.debugf( LOG.debugf(

View File

@ -57,7 +57,7 @@ public class InstantType
@Override @Override
public String getName() { public String getName() {
return Instant.class.getSimpleName(); return "instant";
} }
@Override @Override

View File

@ -46,7 +46,8 @@ public class MaterializedClobType
return typeConfiguration.getBasicTypeRegistry().resolve( return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd, domainJtd,
nclobType nclobType,
getName()
); );
} }

View File

@ -47,7 +47,8 @@ public class PrimitiveCharacterArrayClobType
return typeConfiguration.getBasicTypeRegistry().resolve( return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd, domainJtd,
jdbcTypeRegistry.getDescriptor( Types.NCLOB ) jdbcTypeRegistry.getDescriptor( Types.NCLOB ),
getName()
); );
} }
} }

View File

@ -44,6 +44,6 @@ public interface PrimitiveType<T> extends LiteralType<T>, AdjustableBasicType<T>
@Override @Override
default <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators, JavaTypeDescriptor<X> domainJtd) { default <X> BasicType<X> resolveIndicatedType(JdbcTypeDescriptorIndicators indicators, JavaTypeDescriptor<X> domainJtd) {
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration(); final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, getJdbcTypeDescriptor() ); return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, getJdbcTypeDescriptor(), getName() );
} }
} }

View File

@ -29,11 +29,6 @@ import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.UUID; import java.util.UUID;
import org.hibernate.type.descriptor.java.CharacterArrayTypeDescriptor;
import org.hibernate.type.descriptor.java.PrimitiveCharacterArrayTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NClobTypeDescriptor;
import org.hibernate.type.internal.StandardBasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**
@ -243,11 +238,7 @@ public final class StandardBasicTypes {
* @see #MATERIALIZED_CLOB * @see #MATERIALIZED_CLOB
* @see #TEXT * @see #TEXT
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) public static final CharacterArrayClobType MATERIALIZED_CLOB_CHAR_ARRAY = PrimitiveCharacterArrayClobType.INSTANCE;
public static final StandardBasicTypeImpl<String> MATERIALIZED_CLOB_CHAR_ARRAY = new StandardBasicTypeImpl(
PrimitiveCharacterArrayTypeDescriptor.INSTANCE,
ClobTypeDescriptor.CLOB_BINDING
);
/** /**
@ -256,11 +247,7 @@ public final class StandardBasicTypes {
* @see #MATERIALIZED_CLOB * @see #MATERIALIZED_CLOB
* @see #TEXT * @see #TEXT
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) public static final CharacterArrayClobType MATERIALIZED_CLOB_CHARACTER_ARRAY = CharacterArrayClobType.INSTANCE;
public static final StandardBasicTypeImpl<String> MATERIALIZED_CLOB_CHARACTER_ARRAY = new StandardBasicTypeImpl(
CharacterArrayTypeDescriptor.INSTANCE,
ClobTypeDescriptor.CLOB_BINDING
);
/** /**
@ -269,11 +256,7 @@ public final class StandardBasicTypes {
* @see #MATERIALIZED_NCLOB * @see #MATERIALIZED_NCLOB
* @see #TEXT * @see #TEXT
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) public static final CharacterArrayNClobType MATERIALIZED_NCLOB_CHAR_ARRAY = PrimitiveCharacterArrayNClobType.INSTANCE;
public static final StandardBasicTypeImpl<String> MATERIALIZED_NCLOB_CHAR_ARRAY = new StandardBasicTypeImpl(
PrimitiveCharacterArrayTypeDescriptor.INSTANCE,
NClobTypeDescriptor.NCLOB_BINDING
);
/** /**
@ -282,11 +265,7 @@ public final class StandardBasicTypes {
* @see #NCLOB * @see #NCLOB
* @see #CHAR_ARRAY * @see #CHAR_ARRAY
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) public static final CharacterArrayNClobType MATERIALIZED_NCLOB_CHARACTER_ARRAY = CharacterArrayNClobType.INSTANCE;
public static final StandardBasicTypeImpl<Character[]> MATERIALIZED_NCLOB_CHARACTER_ARRAY = new StandardBasicTypeImpl(
CharacterArrayTypeDescriptor.INSTANCE,
NClobTypeDescriptor.NCLOB_BINDING
);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Date / time data // Date / time data

View File

@ -7,6 +7,7 @@
package org.hibernate.type; package org.hibernate.type;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.query.internal.QueryLiteralHelper;
import org.hibernate.type.descriptor.java.StringTypeDescriptor; import org.hibernate.type.descriptor.java.StringTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NVarcharTypeDescriptor; import org.hibernate.type.descriptor.jdbc.NVarcharTypeDescriptor;
@ -36,7 +37,7 @@ public class StringNVarcharType
} }
public String objectToSQLString(String value, Dialect dialect) throws Exception { public String objectToSQLString(String value, Dialect dialect) throws Exception {
return '\'' + value + '\''; return QueryLiteralHelper.toStringLiteral( value );
} }
public String stringToObject(String xml) throws Exception { public String stringToObject(String xml) throws Exception {

View File

@ -8,6 +8,7 @@ package org.hibernate.type;
import java.sql.Types; import java.sql.Types;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.query.internal.QueryLiteralHelper;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.StringTypeDescriptor; import org.hibernate.type.descriptor.java.StringTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators; import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
@ -41,7 +42,7 @@ public class StringType
} }
public String objectToSQLString(String value, Dialect dialect) throws Exception { public String objectToSQLString(String value, Dialect dialect) throws Exception {
return '\'' + value + '\''; return QueryLiteralHelper.toStringLiteral( value );
} }
public String stringToObject(String xml) throws Exception { public String stringToObject(String xml) throws Exception {
@ -78,7 +79,8 @@ public class StringType
return typeConfiguration.getBasicTypeRegistry().resolve( return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd, domainJtd,
jdbcTypeRegistry.getDescriptor( jdbcTypeCode ) jdbcTypeRegistry.getDescriptor( jdbcTypeCode ),
getName()
); );
} }
} }

View File

@ -48,6 +48,10 @@ public class WrapperBinaryType extends AbstractSingleColumnStandardBasicType<Byt
final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration(); final TypeConfiguration typeConfiguration = indicators.getTypeConfiguration();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry(); final JdbcTypeDescriptorRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeDescriptorRegistry();
return typeConfiguration.getBasicTypeRegistry().resolve( domainJtd, jdbcTypeRegistry.getDescriptor( Types.BLOB ) ); return typeConfiguration.getBasicTypeRegistry().resolve(
domainJtd,
jdbcTypeRegistry.getDescriptor( Types.BLOB ),
getName()
);
} }
} }

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.type.internal;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
/**
* @author Christian Beikov
*/
@SuppressWarnings("rawtypes")
public class NamedStandardBasicTypeImpl<J> extends StandardBasicTypeImpl<J> {
private final String name;
public NamedStandardBasicTypeImpl(JavaTypeDescriptor<J> jtd, JdbcTypeDescriptor std, String name) {
super( jtd, std );
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public BasicType resolveIndicatedType(
JdbcTypeDescriptorIndicators indicators,
JavaTypeDescriptor domainJtd) {
final JdbcTypeDescriptor recommendedSqlType = getJavaTypeDescriptor().getRecommendedJdbcType( indicators );
if ( recommendedSqlType == getJdbcTypeDescriptor() ) {
return this;
}
return indicators.getTypeConfiguration()
.getBasicTypeRegistry()
.resolve( getJavaTypeDescriptor(), recommendedSqlType, getName() );
}
}