Skip to content

Commit

Permalink
HHH-11640 - NamedQuery doesn't log comment when UPDATE/DELETE
Browse files Browse the repository at this point in the history
HHH-11906 - Add support for MySQL query optimizer hints
  • Loading branch information
hradecek authored and vladmihalcea committed Sep 27, 2017
1 parent 08cd580 commit 72506a6
Show file tree
Hide file tree
Showing 16 changed files with 539 additions and 69 deletions.
48 changes: 47 additions & 1 deletion hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java
Expand Up @@ -2788,6 +2788,24 @@ public boolean supportsNotNullUnique() {
return true;
}

/**
* Apply a hint to the query. The entire query is provided, allowing the Dialect full control over the placement
* and syntax of the hint. By default, ignore the hint and simply return the query.
*
* @param query The query to which to apply the hint.
* @param hintList The hints to apply
* @return The modified SQL
*/
public String getQueryHintString(String query, List<String> hintList) {
final String hints = StringHelper.join( ", ", hintList.iterator() );

if ( StringHelper.isEmpty( hints ) ) {
return query;
}

return getQueryHintString( query, hints );
}

/**
* Apply a hint to the query. The entire query is provided, allowing the Dialect full control over the placement
* and syntax of the hint. By default, ignore the hint and simply return the query.
Expand All @@ -2796,7 +2814,7 @@ public boolean supportsNotNullUnique() {
* @param hints The hints to apply
* @return The modified SQL
*/
public String getQueryHintString(String query, List<String> hints) {
public String getQueryHintString(String query, String hints) {
return query;
}

Expand Down Expand Up @@ -2949,4 +2967,32 @@ private void resolveLegacyLimitHandlerBehavior(ServiceRegistry serviceRegistry)
false
);
}

/**
* Modify the SQL, adding hints or comments, if necessary
*
* @param sql original sql
* @param parameters query parameters
* @param commentsEnabled if comments are enabled
*/
public String addSqlHintOrComment(
String sql,
QueryParameters parameters,
boolean commentsEnabled) {

// Keep this here, rather than moving to Select. Some Dialects may need the hint to be appended to the very
// end or beginning of the finalized SQL statement, so wait until everything is processed.
if ( parameters.getQueryHints() != null && parameters.getQueryHints().size() > 0 ) {
sql = getQueryHintString( sql, parameters.getQueryHints() );
}
else if ( commentsEnabled && parameters.getComment() != null ){
sql = prependComment( sql, parameters.getComment() );
}

return sql;
}

protected String prependComment(String sql, String comment) {
return "/* " + comment + " */ " + sql;
}
}
Expand Up @@ -17,6 +17,7 @@
import org.hibernate.dialect.function.NoArgSQLFunction;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.dialect.function.VarArgsSQLFunction;
import org.hibernate.dialect.hint.IndexQueryHintHandler;
import org.hibernate.dialect.identity.H2IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
Expand Down Expand Up @@ -441,4 +442,9 @@ public boolean dropConstraints() {
public IdentityColumnSupport getIdentityColumnSupport() {
return new H2IdentityColumnSupport();
}

@Override
public String getQueryHintString(String query, String hints) {
return IndexQueryHintHandler.INSTANCE.addQueryHints( query, hints );
}
}
Expand Up @@ -9,6 +9,7 @@
import java.sql.SQLException;
import java.sql.Types;

import org.hibernate.dialect.hint.IndexQueryHintHandler;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.util.JdbcExceptionHelper;
Expand Down Expand Up @@ -54,4 +55,9 @@ protected String doExtractConstraintName(SQLException sqle) throws NumberFormatE
}
};


@Override
public String getQueryHintString(String query, String hints) {
return IndexQueryHintHandler.INSTANCE.addQueryHints( query, hints );
}
}
Expand Up @@ -12,6 +12,7 @@
import java.sql.Types;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.JDBCException;
Expand Down Expand Up @@ -65,6 +66,8 @@ public class Oracle8iDialect extends Dialect {

private static final Pattern UNION_KEYWORD_PATTERN = Pattern.compile( "\\bunion\\b" );

private static final Pattern SQL_STATEMENT_TYPE_PATTERN = Pattern.compile("^\\s*(select|insert|update|delete)\\s+.*?");

private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
Expand Down Expand Up @@ -669,21 +672,21 @@ public String getNotExpression( String expression ) {
}

@Override
public String getQueryHintString(String sql, List<String> hints) {
final String hint = StringHelper.join( ", ", hints.iterator() );

if ( StringHelper.isEmpty( hint ) ) {
return sql;
}
public String getQueryHintString(String sql, String hints) {
String statementType = statementType(sql);

final int pos = sql.indexOf( "select" );
final int pos = sql.indexOf( statementType );
if ( pos > -1 ) {
final StringBuilder buffer = new StringBuilder( sql.length() + hint.length() + 8 );
final StringBuilder buffer = new StringBuilder( sql.length() + hints.length() + 8 );
if ( pos > 0 ) {
buffer.append( sql.substring( 0, pos ) );
}
buffer.append( "select /*+ " ).append( hint ).append( " */" )
.append( sql.substring( pos + "select".length() ) );
buffer
.append( statementType )
.append( " /*+ " )
.append( hints )
.append( " */" )
.append( sql.substring( pos + statementType.length() ) );
sql = buffer.toString();
}

Expand Down Expand Up @@ -711,4 +714,14 @@ public boolean canCreateSchema() {
public boolean supportsPartitionBy() {
return true;
}

protected String statementType(String sql) {
Matcher matcher = SQL_STATEMENT_TYPE_PATTERN.matcher( sql );

if(matcher.matches() && matcher.groupCount() == 1) {
return matcher.group(1);
}

throw new IllegalArgumentException( "Can't determine SQL statement type for statement: " + sql );
}
}
Expand Up @@ -55,16 +55,10 @@ public String getQuerySequencesString() {
}

@Override
public String getQueryHintString(String sql, List<String> hints) {
final String hint = StringHelper.join( ", ", hints.iterator() );

if ( StringHelper.isEmpty( hint ) ) {
return sql;
}

public String getQueryHintString(String sql, String hints) {
final StringBuilder buffer = new StringBuilder(
sql.length()
+ hint.length() + 12
+ hints.length() + 12
);
final int pos = sql.indexOf( ";" );
if ( pos > -1 ) {
Expand All @@ -73,7 +67,7 @@ public String getQueryHintString(String sql, List<String> hints) {
else {
buffer.append( sql );
}
buffer.append( " OPTION (" ).append( hint ).append( ")" );
buffer.append( " OPTION (" ).append( hints ).append( ")" );
if ( pos > -1 ) {
buffer.append( ";" );
}
Expand Down
@@ -0,0 +1,48 @@
/*
* 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.dialect.hint;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Adds an INDEX query hint as follows:
*
* <code>
* SELECT *
* FROM TEST
* USE INDEX (hint1, hint2)
* WHERE X=1
* </code>
*
* @author Vlad Mihalcea
*/
public class IndexQueryHintHandler implements QueryHintHandler {

public static final IndexQueryHintHandler INSTANCE = new IndexQueryHintHandler();

private static final Pattern QUERY_PATTERN = Pattern.compile( "^(select.*?from.*?)(where.*?)$" );

@Override
public String addQueryHints(String query, String hints) {
Matcher matcher = QUERY_PATTERN.matcher( query );
if ( matcher.matches() && matcher.groupCount() > 1 ) {
String startToken = matcher.group( 1 );
String endToken = matcher.group( 2 );

return new StringBuilder( startToken )
.append( " USE INDEX (" )
.append( hints )
.append( ") " )
.append( endToken )
.toString();
}
else {
return query;
}
}
}
@@ -0,0 +1,24 @@
/*
* 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.dialect.hint;

/**
* Contract defining how query hints get applied.
*
* @author Vlad Mihalcea
*/
public interface QueryHintHandler {

/**
* Add query hints to the given query.
*
* @param query original query
* @param hints hints to be applied
* @return query with hints
*/
String addQueryHints(String query, String hints);
}
Expand Up @@ -183,7 +183,12 @@ public int performExecuteUpdate(
PreparedStatement ps;
try {
queryParameters.processFilters( this.customQuery.getSQL(), session );
final String sql = queryParameters.getFilteredSQL();
final String sql = session.getJdbcServices().getDialect()
.addSqlHintOrComment(
queryParameters.getFilteredSQL(),
queryParameters,
session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
);

ps = session.getJdbcCoordinator().getStatementPreparer().prepareStatement( sql, false );

Expand Down
Expand Up @@ -56,7 +56,17 @@ public String[] getSqlStatements() {

@Override
public int execute(QueryParameters parameters, SharedSessionContractImplementor session) throws HibernateException {
return doExecute( parameters, session, sql, parameterSpecifications );
return doExecute(
parameters,
session,
session.getJdbcServices().getDialect()
.addSqlHintOrComment(
sql,
parameters,
session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
),
parameterSpecifications
);
}

protected int doExecute(QueryParameters parameters, SharedSessionContractImplementor session, String sql,
Expand Down
34 changes: 12 additions & 22 deletions hibernate-core/src/main/java/org/hibernate/loader/Loader.java
Expand Up @@ -29,6 +29,7 @@
import org.hibernate.QueryException;
import org.hibernate.ScrollMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;
import org.hibernate.WrongClassException;
import org.hibernate.cache.spi.FilterKey;
Expand Down Expand Up @@ -235,21 +236,20 @@ protected String[] getAliases() {
protected String preprocessSQL(
String sql,
QueryParameters parameters,
Dialect dialect,
SessionFactoryImplementor sessionFactory,
List<AfterLoadAction> afterLoadActions) throws HibernateException {
sql = applyLocks( sql, parameters, dialect, afterLoadActions );

// Keep this here, rather than moving to Select. Some Dialects may need the hint to be appended to the very
// end or beginning of the finalized SQL statement, so wait until everything is processed.
if ( parameters.getQueryHints() != null && parameters.getQueryHints().size() > 0 ) {
sql = dialect.getQueryHintString( sql, parameters.getQueryHints() );
}
Dialect dialect = sessionFactory.getServiceRegistry().getService( JdbcServices.class ).getDialect();

sql = processDistinctKeyword( sql, parameters);
sql = applyLocks( sql, parameters, dialect, afterLoadActions );

sql = dialect.addSqlHintOrComment(
sql,
parameters,
sessionFactory.getSessionFactoryOptions().isCommentsEnabled()
);

return getFactory().getSessionFactoryOptions().isCommentsEnabled()
? prependComment( sql, parameters )
: sql;
return processDistinctKeyword( sql, parameters );
}

protected boolean shouldUseFollowOnLocking(
Expand Down Expand Up @@ -299,16 +299,6 @@ protected LockMode determineFollowOnLockMode(LockOptions lockOptions) {
return lockModeToUse;
}

private String prependComment(String sql, QueryParameters parameters) {
String comment = parameters.getComment();
if ( comment == null ) {
return sql;
}
else {
return "/* " + comment + " */ " + sql;
}
}

/**
* Execute an SQL query and attempt to instantiate instances of the class mapped by the given
* persister from each row of the <tt>ResultSet</tt>. If an object is supplied, will attempt to
Expand Down Expand Up @@ -1920,7 +1910,7 @@ protected SqlStatementWrapper executeQueryStatement(
String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters.getRowSelection() );

// Adding locks and comments.
sql = preprocessSQL( sql, queryParameters, getFactory().getDialect(), afterLoadActions );
sql = preprocessSQL( sql, queryParameters, getFactory(), afterLoadActions );

final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );

Expand Down

0 comments on commit 72506a6

Please sign in to comment.