HHH-13496 Pre-compile and reuse regular expressions

This commit is contained in:
Sanne Grinovero 2019-07-05 22:21:10 +01:00
parent bfc66ec356
commit 70d33e0c6b
8 changed files with 130 additions and 89 deletions

View File

@ -9,12 +9,21 @@ package org.hibernate.boot.model.source.internal.hbm;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.hibernate.internal.util.StringHelper;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
* @author Sanne Grinovero
*/ */
public class CommaSeparatedStringHelper { public final class CommaSeparatedStringHelper {
private static final Pattern COMMA_SEPARATED_PATTERN = Pattern.compile( "\\s*,\\s*" );
private CommaSeparatedStringHelper() { private CommaSeparatedStringHelper() {
} }
@ -22,21 +31,25 @@ public class CommaSeparatedStringHelper {
if ( values == null || values.isEmpty() ) { if ( values == null || values.isEmpty() ) {
return Collections.emptySet(); return Collections.emptySet();
} }
return COMMA_SEPARATED_PATTERN.splitAsStream( values ).collect( Collectors.toSet() );
HashSet<String> set = new HashSet<String>();
Collections.addAll( set, values.split( "\\s*,\\s*" ) );
return set;
} }
public static Set<String> splitAndCombine(Set<String> x, String values) { public static Set<String> splitAndCombine(Set<String> x, String values) {
if ( x.isEmpty() && (values == null || values.isEmpty()) ) { if ( x.isEmpty() && ( values == null || values.isEmpty() ) ) {
return Collections.emptySet(); return Collections.emptySet();
} }
HashSet<String> set = new HashSet<String>( x ); HashSet<String> set = new HashSet<String>( x );
if ( values != null && !values.isEmpty() ) { if ( values != null && !values.isEmpty() ) {
Collections.addAll( set, values.split( "\\s*,\\s*" ) ); Collections.addAll( set, COMMA_SEPARATED_PATTERN.split( values ) );
} }
return set; return set;
} }
public static List<String> parseCommaSeparatedString(String incomingString) {
if ( StringHelper.isEmpty( incomingString ) ) {
return Collections.emptyList();
}
return COMMA_SEPARATED_PATTERN.splitAsStream( incomingString ).collect( Collectors.toList() );
}
} }

View File

@ -6,6 +6,9 @@
*/ */
package org.hibernate.boot.model.source.spi; package org.hibernate.boot.model.source.spi;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
/** /**
@ -14,6 +17,11 @@ import org.hibernate.internal.util.StringHelper;
public abstract class AbstractAttributeKey { public abstract class AbstractAttributeKey {
// todo : replace this with "{element}" // todo : replace this with "{element}"
private static final String COLLECTION_ELEMENT = "collection&&element"; private static final String COLLECTION_ELEMENT = "collection&&element";
private static final String DOT_COLLECTION_ELEMENT = '.' + COLLECTION_ELEMENT;
private static final Pattern DOT_COLLECTION_ELEMENT_PATTERN = Pattern.compile(
DOT_COLLECTION_ELEMENT,
Pattern.LITERAL
);
private final AbstractAttributeKey parent; private final AbstractAttributeKey parent;
private final String property; private final String property;
@ -130,11 +138,11 @@ public abstract class AbstractAttributeKey {
* marker ({@link #COLLECTION_ELEMENT}. * marker ({@link #COLLECTION_ELEMENT}.
*/ */
public boolean isPartOfCollectionElement() { public boolean isPartOfCollectionElement() {
return fullPath.contains( '.' + COLLECTION_ELEMENT ); return fullPath.contains( DOT_COLLECTION_ELEMENT );
} }
public String stripCollectionElementMarker() { public String stripCollectionElementMarker() {
return fullPath.replace( '.' + COLLECTION_ELEMENT, "" ); return DOT_COLLECTION_ELEMENT_PATTERN.matcher( fullPath ).replaceAll( Matcher.quoteReplacement( "" ) );
} }
@Override @Override

View File

@ -14,6 +14,7 @@ import java.sql.Clob;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.NClob; import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
@ -25,12 +26,17 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.Criteria;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.NullPrecedence; import org.hibernate.NullPrecedence;
import org.hibernate.Query;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
@ -73,6 +79,7 @@ import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
import org.hibernate.hql.spi.id.persistent.PersistentTableBulkIdStrategy; import org.hibernate.hql.spi.id.persistent.PersistentTableBulkIdStrategy;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.IdentityGenerator; import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.enhanced.SequenceStyleGenerator; import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
@ -96,6 +103,7 @@ import org.hibernate.sql.ANSIJoinFragment;
import org.hibernate.sql.CaseFragment; import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.ForUpdateFragment; import org.hibernate.sql.ForUpdateFragment;
import org.hibernate.sql.JoinFragment; import org.hibernate.sql.JoinFragment;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
@ -107,6 +115,7 @@ import org.hibernate.tool.schema.internal.StandardTableExporter;
import org.hibernate.tool.schema.internal.StandardUniqueKeyExporter; import org.hibernate.tool.schema.internal.StandardUniqueKeyExporter;
import org.hibernate.tool.schema.spi.Exporter; import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
@ -140,6 +149,11 @@ public abstract class Dialect implements ConversionContext {
* Characters used as closing for quoting SQL identifiers * Characters used as closing for quoting SQL identifiers
*/ */
public static final String CLOSED_QUOTE = "`\"]"; public static final String CLOSED_QUOTE = "`\"]";
private static final Pattern SINGLE_QUOTE_PATTERN = Pattern.compile(
"'",
Pattern.LITERAL
);
public static final String TWO_SINGLE_QUOTES_REPLACEMENT = Matcher.quoteReplacement( "''" );
private final TypeNames typeNames = new TypeNames(); private final TypeNames typeNames = new TypeNames();
private final TypeNames hibernateTypeNames = new TypeNames(); private final TypeNames hibernateTypeNames = new TypeNames();
@ -325,9 +339,9 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Get the name of the database type associated with the given * Get the name of the database type associated with the given
* {@link java.sql.Types} typecode. * {@link Types} typecode.
* *
* @param code The {@link java.sql.Types} typecode * @param code The {@link Types} typecode
* @return the database type name * @return the database type name
* @throws HibernateException If no mapping was specified for that type. * @throws HibernateException If no mapping was specified for that type.
*/ */
@ -341,10 +355,10 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Get the name of the database type associated with the given * Get the name of the database type associated with the given
* {@link java.sql.Types} typecode with the given storage specification * {@link Types} typecode with the given storage specification
* parameters. * parameters.
* *
* @param code The {@link java.sql.Types} typecode * @param code The {@link Types} typecode
* @param length The datatype length * @param length The datatype length
* @param precision The datatype precision * @param precision The datatype precision
* @param scale The datatype scale * @param scale The datatype scale
@ -363,9 +377,9 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Get the name of the database type appropriate for casting operations * Get the name of the database type appropriate for casting operations
* (via the CAST() SQL function) for the given {@link java.sql.Types} typecode. * (via the CAST() SQL function) for the given {@link Types} typecode.
* *
* @param code The {@link java.sql.Types} typecode * @param code The {@link Types} typecode
* @return The database type name * @return The database type name
*/ */
public String getCastTypeName(int code) { public String getCastTypeName(int code) {
@ -427,7 +441,7 @@ public abstract class Dialect implements ConversionContext {
* column length. <tt>$l</tt> in the type name with be replaced by the * column length. <tt>$l</tt> in the type name with be replaced by the
* column length (if appropriate). * column length (if appropriate).
* *
* @param code The {@link java.sql.Types} typecode * @param code The {@link Types} typecode
* @param capacity The maximum length of database type * @param capacity The maximum length of database type
* @param name The database type name * @param name The database type name
*/ */
@ -439,7 +453,7 @@ public abstract class Dialect implements ConversionContext {
* Subclasses register a type name for the given type code. <tt>$l</tt> in * Subclasses register a type name for the given type code. <tt>$l</tt> in
* the type name with be replaced by the column length (if appropriate). * the type name with be replaced by the column length (if appropriate).
* *
* @param code The {@link java.sql.Types} typecode * @param code The {@link Types} typecode
* @param name The database type name * @param name The database type name
*/ */
protected void registerColumnType(int code, String name) { protected void registerColumnType(int code, String name) {
@ -450,7 +464,7 @@ public abstract class Dialect implements ConversionContext {
* Allows the dialect to override a {@link SqlTypeDescriptor}. * Allows the dialect to override a {@link SqlTypeDescriptor}.
* <p/> * <p/>
* If the passed {@code sqlTypeDescriptor} allows itself to be remapped (per * If the passed {@code sqlTypeDescriptor} allows itself to be remapped (per
* {@link org.hibernate.type.descriptor.sql.SqlTypeDescriptor#canBeRemapped()}), then this method uses * {@link SqlTypeDescriptor#canBeRemapped()}), then this method uses
* {@link #getSqlTypeDescriptorOverride} to get an optional override based on the SQL code returned by * {@link #getSqlTypeDescriptorOverride} to get an optional override based on the SQL code returned by
* {@link SqlTypeDescriptor#getSqlType()}. * {@link SqlTypeDescriptor#getSqlType()}.
* <p/> * <p/>
@ -648,11 +662,11 @@ public abstract class Dialect implements ConversionContext {
// hibernate type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // hibernate type mapping support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** /**
* Get the name of the Hibernate {@link org.hibernate.type.Type} associated with the given * Get the name of the Hibernate {@link Type} associated with the given
* {@link java.sql.Types} type code. * {@link Types} type code.
* *
* @param code The {@link java.sql.Types} type code * @param code The {@link Types} type code
* @return The Hibernate {@link org.hibernate.type.Type} name. * @return The Hibernate {@link Type} name.
* @throws HibernateException If no mapping was specified for that type. * @throws HibernateException If no mapping was specified for that type.
*/ */
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings( {"UnusedDeclaration"})
@ -677,15 +691,15 @@ public abstract class Dialect implements ConversionContext {
} }
/** /**
* Get the name of the Hibernate {@link org.hibernate.type.Type} associated * Get the name of the Hibernate {@link Type} associated
* with the given {@link java.sql.Types} typecode with the given storage * with the given {@link Types} typecode with the given storage
* specification parameters. * specification parameters.
* *
* @param code The {@link java.sql.Types} typecode * @param code The {@link Types} typecode
* @param length The datatype length * @param length The datatype length
* @param precision The datatype precision * @param precision The datatype precision
* @param scale The datatype scale * @param scale The datatype scale
* @return The Hibernate {@link org.hibernate.type.Type} name. * @return The Hibernate {@link Type} name.
* @throws HibernateException If no mapping was specified for that type. * @throws HibernateException If no mapping was specified for that type.
*/ */
public String getHibernateTypeName(int code, int length, int precision, int scale) throws HibernateException { public String getHibernateTypeName(int code, int length, int precision, int scale) throws HibernateException {
@ -703,23 +717,23 @@ public abstract class Dialect implements ConversionContext {
} }
/** /**
* Registers a Hibernate {@link org.hibernate.type.Type} name for the given * Registers a Hibernate {@link Type} name for the given
* {@link java.sql.Types} type code and maximum column length. * {@link Types} type code and maximum column length.
* *
* @param code The {@link java.sql.Types} typecode * @param code The {@link Types} typecode
* @param capacity The maximum length of database type * @param capacity The maximum length of database type
* @param name The Hibernate {@link org.hibernate.type.Type} name * @param name The Hibernate {@link Type} name
*/ */
protected void registerHibernateType(int code, long capacity, String name) { protected void registerHibernateType(int code, long capacity, String name) {
hibernateTypeNames.put( code, capacity, name ); hibernateTypeNames.put( code, capacity, name );
} }
/** /**
* Registers a Hibernate {@link org.hibernate.type.Type} name for the given * Registers a Hibernate {@link Type} name for the given
* {@link java.sql.Types} type code. * {@link Types} type code.
* *
* @param code The {@link java.sql.Types} typecode * @param code The {@link Types} typecode
* @param name The Hibernate {@link org.hibernate.type.Type} name * @param name The Hibernate {@link Type} name
*/ */
protected void registerHibernateType(int code, String name) { protected void registerHibernateType(int code, String name) {
hibernateTypeNames.put( code, name ); hibernateTypeNames.put( code, name );
@ -736,7 +750,7 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Retrieves a map of the dialect's registered functions * Retrieves a map of the dialect's registered functions
* (functionName => {@link org.hibernate.dialect.function.SQLFunction}). * (functionName => {@link SQLFunction}).
* *
* @return The map of registered functions. * @return The map of registered functions.
*/ */
@ -748,7 +762,7 @@ public abstract class Dialect implements ConversionContext {
// native identifier generation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // native identifier generation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** /**
* The class (which implements {@link org.hibernate.id.IdentifierGenerator}) * The class (which implements {@link IdentifierGenerator})
* which acts as this dialects native generation strategy. * which acts as this dialects native generation strategy.
* <p/> * <p/>
* Comes into play whenever the user specifies the native generator. * Comes into play whenever the user specifies the native generator.
@ -947,7 +961,7 @@ public abstract class Dialect implements ConversionContext {
* Get the select command used retrieve the names of all sequences. * Get the select command used retrieve the names of all sequences.
* *
* @return The select command; or null if sequences are not supported. * @return The select command; or null if sequences are not supported.
* @see org.hibernate.tool.hbm2ddl.SchemaUpdate * @see SchemaUpdate
*/ */
public String getQuerySequencesString() { public String getQuerySequencesString() {
return null; return null;
@ -1129,8 +1143,8 @@ public abstract class Dialect implements ConversionContext {
* *
* @param zeroBasedFirstResult The user-supplied, zero-based first row offset. * @param zeroBasedFirstResult The user-supplied, zero-based first row offset.
* @return The corresponding db/dialect specific offset. * @return The corresponding db/dialect specific offset.
* @see org.hibernate.Query#setFirstResult * @see Query#setFirstResult
* @see org.hibernate.Criteria#setFirstResult * @see Criteria#setFirstResult
* @deprecated {@link #getLimitHandler()} should be overridden instead. * @deprecated {@link #getLimitHandler()} should be overridden instead.
*/ */
@Deprecated @Deprecated
@ -1156,7 +1170,7 @@ public abstract class Dialect implements ConversionContext {
* If this dialect supports specifying lock timeouts, are those timeouts * If this dialect supports specifying lock timeouts, are those timeouts
* rendered into the <tt>SQL</tt> string as parameters. The implication * rendered into the <tt>SQL</tt> string as parameters. The implication
* is that Hibernate will need to bind the timeout value as a parameter * is that Hibernate will need to bind the timeout value as a parameter
* in the {@link java.sql.PreparedStatement}. If true, the param position * in the {@link PreparedStatement}. If true, the param position
* is always handled as the last parameter; if the dialect specifies the * is always handled as the last parameter; if the dialect specifies the
* lock timeout elsewhere in the <tt>SQL</tt> statement then the timeout * lock timeout elsewhere in the <tt>SQL</tt> statement then the timeout
* value should be directly rendered into the statement and this method * value should be directly rendered into the statement and this method
@ -1498,7 +1512,7 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Registers a parameter (either OUT, or the new REF_CURSOR param type available in Java 8) capable of * Registers a parameter (either OUT, or the new REF_CURSOR param type available in Java 8) capable of
* returning {@link java.sql.ResultSet} *by position*. Pre-Java 8, registering such ResultSet-returning * returning {@link ResultSet} *by position*. Pre-Java 8, registering such ResultSet-returning
* parameters varied greatly across database and drivers; hence its inclusion as part of the Dialect contract. * parameters varied greatly across database and drivers; hence its inclusion as part of the Dialect contract.
* *
* @param statement The callable statement. * @param statement The callable statement.
@ -1517,7 +1531,7 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Registers a parameter (either OUT, or the new REF_CURSOR param type available in Java 8) capable of * Registers a parameter (either OUT, or the new REF_CURSOR param type available in Java 8) capable of
* returning {@link java.sql.ResultSet} *by name*. Pre-Java 8, registering such ResultSet-returning * returning {@link ResultSet} *by name*. Pre-Java 8, registering such ResultSet-returning
* parameters varied greatly across database and drivers; hence its inclusion as part of the Dialect contract. * parameters varied greatly across database and drivers; hence its inclusion as part of the Dialect contract.
* *
* @param statement The callable statement. * @param statement The callable statement.
@ -1537,7 +1551,7 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Given a callable statement previously processed by {@link #registerResultSetOutParameter}, * Given a callable statement previously processed by {@link #registerResultSetOutParameter},
* extract the {@link java.sql.ResultSet} from the OUT parameter. * extract the {@link ResultSet} from the OUT parameter.
* *
* @param statement The callable statement. * @param statement The callable statement.
* @return The extracted result set. * @return The extracted result set.
@ -1551,7 +1565,7 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Given a callable statement previously processed by {@link #registerResultSetOutParameter}, * Given a callable statement previously processed by {@link #registerResultSetOutParameter},
* extract the {@link java.sql.ResultSet}. * extract the {@link ResultSet}.
* *
* @param statement The callable statement. * @param statement The callable statement.
* @param position The bind position at which to register the output param. * @param position The bind position at which to register the output param.
@ -1569,7 +1583,7 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Given a callable statement previously processed by {@link #registerResultSetOutParameter}, * Given a callable statement previously processed by {@link #registerResultSetOutParameter},
* extract the {@link java.sql.ResultSet} from the OUT parameter. * extract the {@link ResultSet} from the OUT parameter.
* *
* @param statement The callable statement. * @param statement The callable statement.
* @param name The parameter name (for drivers which support named parameters). * @param name The parameter name (for drivers which support named parameters).
@ -1711,14 +1725,14 @@ public abstract class Dialect implements ConversionContext {
// union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** /**
* Given a {@link java.sql.Types} type code, determine an appropriate * Given a {@link Types} type code, determine an appropriate
* null value to use in a select clause. * null value to use in a select clause.
* <p/> * <p/>
* One thing to consider here is that certain databases might * One thing to consider here is that certain databases might
* require proper casting for the nulls here since the select here * require proper casting for the nulls here since the select here
* will be part of a UNION/UNION ALL. * will be part of a UNION/UNION ALL.
* *
* @param sqlType The {@link java.sql.Types} type code. * @param sqlType The {@link Types} type code.
* @return The appropriate select clause value fragment. * @return The appropriate select clause value fragment.
*/ */
public String getSelectClauseNullString(int sqlType) { public String getSelectClauseNullString(int sqlType) {
@ -1740,21 +1754,21 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Create a {@link org.hibernate.sql.JoinFragment} strategy responsible * Create a {@link JoinFragment} strategy responsible
* for handling this dialect's variations in how joins are handled. * for handling this dialect's variations in how joins are handled.
* *
* @return This dialect's {@link org.hibernate.sql.JoinFragment} strategy. * @return This dialect's {@link JoinFragment} strategy.
*/ */
public JoinFragment createOuterJoinFragment() { public JoinFragment createOuterJoinFragment() {
return new ANSIJoinFragment(); return new ANSIJoinFragment();
} }
/** /**
* Create a {@link org.hibernate.sql.CaseFragment} strategy responsible * Create a {@link CaseFragment} strategy responsible
* for handling this dialect's variations in how CASE statements are * for handling this dialect's variations in how CASE statements are
* handled. * handled.
* *
* @return This dialect's {@link org.hibernate.sql.CaseFragment} strategy. * @return This dialect's {@link CaseFragment} strategy.
*/ */
public CaseFragment createCaseFragment() { public CaseFragment createCaseFragment() {
return new ANSICaseFragment(); return new ANSICaseFragment();
@ -1813,7 +1827,7 @@ public abstract class Dialect implements ConversionContext {
* to the database and perhaps manipulate them in some fashion. * to the database and perhaps manipulate them in some fashion.
* <p/> * <p/>
* The recommend approach is to instead use * The recommend approach is to instead use
* {@link org.hibernate.Interceptor#onPrepareStatement(String)}. * {@link Interceptor#onPrepareStatement(String)}.
* *
* @param select The select command * @param select The select command
* @return The mutated select command, or the same as was passed in. * @return The mutated select command, or the same as was passed in.
@ -2052,7 +2066,7 @@ public abstract class Dialect implements ConversionContext {
* Get the SQL command used to retrieve the current schema name. Works in conjunction * Get the SQL command used to retrieve the current schema name. Works in conjunction
* with {@link #getSchemaNameResolver()}, unless the return from there does not need this * with {@link #getSchemaNameResolver()}, unless the return from there does not need this
* information. E.g., a custom impl might make use of the Java 1.7 addition of * information. E.g., a custom impl might make use of the Java 1.7 addition of
* the {@link java.sql.Connection#getSchema()} method * the {@link Connection#getSchema()} method
* *
* @return The current schema retrieval SQL * @return The current schema retrieval SQL
*/ */
@ -2418,7 +2432,7 @@ public abstract class Dialect implements ConversionContext {
/** /**
* Should LOBs (both BLOB and CLOB) be bound using stream operations (i.e. * Should LOBs (both BLOB and CLOB) be bound using stream operations (i.e.
* {@link java.sql.PreparedStatement#setBinaryStream}). * {@link PreparedStatement#setBinaryStream}).
* *
* @return True if BLOBs and CLOBs should be bound using stream operations. * @return True if BLOBs and CLOBs should be bound using stream operations.
* @since 3.2 * @since 3.2
@ -2493,14 +2507,14 @@ public abstract class Dialect implements ConversionContext {
* Does this dialect support asking the result set its positioning * Does this dialect support asking the result set its positioning
* information on forward only cursors. Specifically, in the case of * information on forward only cursors. Specifically, in the case of
* scrolling fetches, Hibernate needs to use * scrolling fetches, Hibernate needs to use
* {@link java.sql.ResultSet#isAfterLast} and * {@link ResultSet#isAfterLast} and
* {@link java.sql.ResultSet#isBeforeFirst}. Certain drivers do not * {@link ResultSet#isBeforeFirst}. Certain drivers do not
* allow access to these methods for forward only cursors. * allow access to these methods for forward only cursors.
* <p/> * <p/>
* NOTE : this is highly driver dependent! * NOTE : this is highly driver dependent!
* *
* @return True if methods like {@link java.sql.ResultSet#isAfterLast} and * @return True if methods like {@link ResultSet#isAfterLast} and
* {@link java.sql.ResultSet#isBeforeFirst} are supported for forward * {@link ResultSet#isBeforeFirst} are supported for forward
* only cursors; false otherwise. * only cursors; false otherwise.
* @since 3.2 * @since 3.2
*/ */
@ -2559,17 +2573,17 @@ public abstract class Dialect implements ConversionContext {
* locator instance... * locator instance...
* <p/> * <p/>
* For BLOBs, the internal value might be changed by: * For BLOBs, the internal value might be changed by:
* {@link java.sql.Blob#setBinaryStream}, * {@link Blob#setBinaryStream},
* {@link java.sql.Blob#setBytes(long, byte[])}, * {@link Blob#setBytes(long, byte[])},
* {@link java.sql.Blob#setBytes(long, byte[], int, int)}, * {@link Blob#setBytes(long, byte[], int, int)},
* or {@link java.sql.Blob#truncate(long)}. * or {@link Blob#truncate(long)}.
* <p/> * <p/>
* For CLOBs, the internal value might be changed by: * For CLOBs, the internal value might be changed by:
* {@link java.sql.Clob#setAsciiStream(long)}, * {@link Clob#setAsciiStream(long)},
* {@link java.sql.Clob#setCharacterStream(long)}, * {@link Clob#setCharacterStream(long)},
* {@link java.sql.Clob#setString(long, String)}, * {@link Clob#setString(long, String)},
* {@link java.sql.Clob#setString(long, String, int, int)}, * {@link Clob#setString(long, String, int, int)},
* or {@link java.sql.Clob#truncate(long)}. * or {@link Clob#truncate(long)}.
* <p/> * <p/>
* NOTE : I do not know the correct answer currently for * NOTE : I do not know the correct answer currently for
* databases which (1) are not part of the cruise control process * databases which (1) are not part of the cruise control process
@ -2976,7 +2990,7 @@ public abstract class Dialect implements ConversionContext {
} }
/** /**
* Check whether the JDBC {@link java.sql.Connection} supports creating LOBs via {@link Connection#createBlob()}, * Check whether the JDBC {@link Connection} supports creating LOBs via {@link Connection#createBlob()},
* {@link Connection#createNClob()} or {@link Connection#createClob()}. * {@link Connection#createNClob()} or {@link Connection#createClob()}.
* *
* @param databaseMetaData JDBC {@link DatabaseMetaData} which can be used if LOB creation is supported only starting from a given Driver version * @param databaseMetaData JDBC {@link DatabaseMetaData} which can be used if LOB creation is supported only starting from a given Driver version
@ -2993,7 +3007,7 @@ public abstract class Dialect implements ConversionContext {
* @return escaped String * @return escaped String
*/ */
protected String escapeLiteral(String literal) { protected String escapeLiteral(String literal) {
return literal.replace("'", "''"); return SINGLE_QUOTE_PATTERN.matcher( literal ).replaceAll( TWO_SINGLE_QUOTES_REPLACEMENT );
} }
private void resolveLegacyLimitHandlerBehavior(ServiceRegistry serviceRegistry) { private void resolveLegacyLimitHandlerBehavior(ServiceRegistry serviceRegistry) {

View File

@ -10,6 +10,8 @@ import java.sql.CallableStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.JDBCException; import org.hibernate.JDBCException;
import org.hibernate.NullPrecedence; import org.hibernate.NullPrecedence;
@ -45,6 +47,12 @@ import org.hibernate.type.StandardBasicTypes;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class MySQLDialect extends Dialect { public class MySQLDialect extends Dialect {
private static final Pattern ESCAPE_PATTERN = Pattern.compile(
"\\",
Pattern.LITERAL
);
public static final String ESCAPE_PATTERN_REPLACEMENT = Matcher.quoteReplacement(
"\\\\" );
private final UniqueDelegate uniqueDelegate; private final UniqueDelegate uniqueDelegate;
private final MySQLStorageEngine storageEngine; private final MySQLStorageEngine storageEngine;
@ -593,6 +601,6 @@ public class MySQLDialect extends Dialect {
@Override @Override
protected String escapeLiteral(String literal) { protected String escapeLiteral(String literal) {
return super.escapeLiteral( literal ).replace("\\", "\\\\"); return ESCAPE_PATTERN.matcher( super.escapeLiteral( literal ) ).replaceAll( ESCAPE_PATTERN_REPLACEMENT );
} }
} }

View File

@ -16,6 +16,7 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.hibernate.boot.model.source.internal.hbm.CommaSeparatedStringHelper;
import org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport; import org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport;
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
@ -207,12 +208,7 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData
} }
private Set<String> parseKeywords(String extraKeywordsString) { private Set<String> parseKeywords(String extraKeywordsString) {
if ( StringHelper.isEmpty( extraKeywordsString ) ) { return CommaSeparatedStringHelper.split( extraKeywordsString );
return Collections.emptySet();
}
final Set<String> keywordSet = new HashSet<String>( Arrays.asList( extraKeywordsString.split( "\\s*,\\s*" ) ) );
return keywordSet;
} }
public Builder setConnectionSchemaName(String connectionSchemaName) { public Builder setConnectionSchemaName(String connectionSchemaName) {

View File

@ -63,10 +63,6 @@ public class IdentifierHelperBuilder {
} }
private static List<String> parseKeywords(String extraKeywordsString) { private static List<String> parseKeywords(String extraKeywordsString) {
if ( StringHelper.isEmpty( extraKeywordsString ) ) {
return Collections.emptyList();
}
return StringHelper.parseCommaSeparatedString( extraKeywordsString ); return StringHelper.parseCommaSeparatedString( extraKeywordsString );
} }

View File

@ -20,6 +20,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.regex.Pattern;
import javax.naming.Reference; import javax.naming.Reference;
import javax.naming.StringRefAddr; import javax.naming.StringRefAddr;
import javax.persistence.EntityGraph; import javax.persistence.EntityGraph;
@ -108,7 +109,9 @@ import org.hibernate.persister.entity.Loadable;
import org.hibernate.procedure.ProcedureCall; import org.hibernate.procedure.ProcedureCall;
import org.hibernate.proxy.EntityNotFoundDelegate; import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.proxy.HibernateProxyHelper; import org.hibernate.proxy.HibernateProxyHelper;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl; import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.spi.NamedQueryRepository;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector; import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.AfterCompletionAction; import org.hibernate.resource.transaction.backend.jta.internal.synchronization.AfterCompletionAction;
@ -155,6 +158,7 @@ import static org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting.det
*/ */
public final class SessionFactoryImpl implements SessionFactoryImplementor { public final class SessionFactoryImpl implements SessionFactoryImplementor {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SessionFactoryImpl.class ); private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SessionFactoryImpl.class );
private static final Pattern LISTENER_SEPARATION_PATTERN = Pattern.compile( " ," );
private final String name; private final String name;
private final String uuid; private final String uuid;
@ -178,7 +182,7 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
private final transient CriteriaBuilderImpl criteriaBuilder; private final transient CriteriaBuilderImpl criteriaBuilder;
private final PersistenceUnitUtil jpaPersistenceUnitUtil; private final PersistenceUnitUtil jpaPersistenceUnitUtil;
private final transient CacheImplementor cacheAccess; private final transient CacheImplementor cacheAccess;
private final transient org.hibernate.query.spi.NamedQueryRepository namedQueryRepository; private final transient NamedQueryRepository namedQueryRepository;
private final transient QueryPlanCache queryPlanCache; private final transient QueryPlanCache queryPlanCache;
private final transient CurrentSessionContext currentSessionContext; private final transient CurrentSessionContext currentSessionContext;
@ -410,7 +414,7 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
); );
final EventType eventType = EventType.resolveEventTypeByName( eventTypeName ); final EventType eventType = EventType.resolveEventTypeByName( eventTypeName );
final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType ); final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType );
for ( String listenerImpl : ( (String) entry.getValue() ).split( " ," ) ) { for ( String listenerImpl : LISTENER_SEPARATION_PATTERN.split( ( (String) entry.getValue() ) ) ) {
eventListenerGroup.appendListener( instantiate( listenerImpl, classLoaderService ) ); eventListenerGroup.appendListener( instantiate( listenerImpl, classLoaderService ) );
} }
} }
@ -712,7 +716,7 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
} }
@Override @Override
public org.hibernate.query.spi.NamedQueryRepository getNamedQueryRepository() { public NamedQueryRepository getNamedQueryRepository() {
return namedQueryRepository; return namedQueryRepository;
} }
@ -863,10 +867,10 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
org.hibernate.query.Query hibernateQuery = query.unwrap( org.hibernate.query.Query.class ); org.hibernate.query.Query hibernateQuery = query.unwrap( org.hibernate.query.Query.class );
if ( hibernateQuery != null ) { if ( hibernateQuery != null ) {
// create and register the proper NamedQueryDefinition... // create and register the proper NamedQueryDefinition...
if ( org.hibernate.query.NativeQuery.class.isInstance( hibernateQuery ) ) { if ( NativeQuery.class.isInstance( hibernateQuery ) ) {
getNamedQueryRepository().registerNamedSQLQueryDefinition( getNamedQueryRepository().registerNamedSQLQueryDefinition(
name, name,
extractSqlQueryDefinition( (org.hibernate.query.NativeQuery) hibernateQuery, name ) extractSqlQueryDefinition( (NativeQuery) hibernateQuery, name )
); );
} }
else { else {
@ -898,7 +902,7 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
); );
} }
private NamedSQLQueryDefinition extractSqlQueryDefinition(org.hibernate.query.NativeQuery nativeSqlQuery, String name) { private NamedSQLQueryDefinition extractSqlQueryDefinition(NativeQuery nativeSqlQuery, String name) {
final NamedSQLQueryDefinitionBuilder builder = new NamedSQLQueryDefinitionBuilder( name ); final NamedSQLQueryDefinitionBuilder builder = new NamedSQLQueryDefinitionBuilder( name );
fillInNamedQueryBuilder( builder, nativeSqlQuery ); fillInNamedQueryBuilder( builder, nativeSqlQuery );
builder.setCallable( nativeSqlQuery.isCallable() ) builder.setCallable( nativeSqlQuery.isCallable() )

View File

@ -15,7 +15,9 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.hibernate.boot.model.source.internal.hbm.CommaSeparatedStringHelper;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.ArrayHelper;
@ -700,8 +702,8 @@ public final class StringHelper {
* Determine if the given name is quoted. It is considered quoted if either: * Determine if the given name is quoted. It is considered quoted if either:
* <ol> * <ol>
* <li>starts AND ends with backticks (`)</li> * <li>starts AND ends with backticks (`)</li>
* <li>starts with dialect-specified {@link org.hibernate.dialect.Dialect#openQuote() open-quote} * <li>starts with dialect-specified {@link Dialect#openQuote() open-quote}
* AND ends with dialect-specified {@link org.hibernate.dialect.Dialect#closeQuote() close-quote}</li> * AND ends with dialect-specified {@link Dialect#closeQuote() close-quote}</li>
* </ol> * </ol>
* *
* @param name The name to check * @param name The name to check
@ -835,7 +837,7 @@ public final class StringHelper {
} }
public static List<String> parseCommaSeparatedString(String incomingString) { public static List<String> parseCommaSeparatedString(String incomingString) {
return Arrays.asList( incomingString.split( "\\s*,\\s*" ) ); return CommaSeparatedStringHelper.parseCommaSeparatedString( incomingString );
} }
public static <T> String join(Collection<T> values, Renderer<T> renderer) { public static <T> String join(Collection<T> values, Renderer<T> renderer) {