HHH-9190 Introducing QueryPlanFactory service contract in order to make creation of native query plans customizable

This commit is contained in:
Gunnar Morling 2014-05-19 14:23:13 +02:00 committed by Steve Ebersole
parent ccdf6df3d6
commit ac06799a55
6 changed files with 178 additions and 21 deletions

View File

@ -0,0 +1,51 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.query.spi;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.loader.custom.sql.SQLCustomQuery;
/**
* Default query plan factory used by Hibernate ORM. Creates query plans for SQL
* queries.
*
* @author Gunnar Morling
*
*/
public class DefaultQueryPlanFactory implements QueryPlanFactory {
@Override
public NativeSQLQueryPlan createNativeQueryPlan(NativeSQLQuerySpecification nativeQuerySpecification, SessionFactoryImplementor sessionFactory) {
CustomQuery customQuery = new SQLCustomQuery(
nativeQuerySpecification.getQueryString(),
nativeQuerySpecification.getQueryReturns(),
nativeQuerySpecification.getQuerySpaces(),
sessionFactory
);
return new NativeSQLQueryPlan( nativeQuerySpecification.getQueryString(), customQuery );
}
}

View File

@ -33,16 +33,14 @@ import java.util.Map;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.action.internal.BulkOperationCleanupAction; import org.hibernate.action.internal.BulkOperationCleanupAction;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.TypedValue; import org.hibernate.engine.spi.TypedValue;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.custom.sql.SQLCustomQuery; import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.type.Type; import org.hibernate.type.Type;
/** /**
@ -54,31 +52,24 @@ public class NativeSQLQueryPlan implements Serializable {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( NativeSQLQueryPlan.class ); private static final CoreMessageLogger LOG = CoreLogging.messageLogger( NativeSQLQueryPlan.class );
private final String sourceQuery; private final String sourceQuery;
private final SQLCustomQuery customQuery; private final CustomQuery customQuery;
/** /**
* Constructs a NativeSQLQueryPlan * Constructs a NativeSQLQueryPlan.
* *
* @param specification The query spec * @param sourceQuery The original native query to create a plan for
* @param factory The SessionFactory * @param customQuery The query executed via this plan
*/ */
public NativeSQLQueryPlan( public NativeSQLQueryPlan(String sourceQuery, CustomQuery customQuery) {
NativeSQLQuerySpecification specification, this.sourceQuery = sourceQuery;
SessionFactoryImplementor factory) { this.customQuery = customQuery;
this.sourceQuery = specification.getQueryString();
this.customQuery = new SQLCustomQuery(
specification.getQueryString(),
specification.getQueryReturns(),
specification.getQuerySpaces(),
factory
);
} }
public String getSourceQuery() { public String getSourceQuery() {
return sourceQuery; return sourceQuery;
} }
public SQLCustomQuery getCustomQuery() { public CustomQuery getCustomQuery() {
return customQuery; return customQuery;
} }

View File

@ -222,7 +222,10 @@ public class QueryPlanCache implements Serializable {
NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec ); NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec );
if ( value == null ) { if ( value == null ) {
LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() ); LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() );
value = new NativeSQLQueryPlan( spec, factory); value = factory.getServiceRegistry()
.getService(QueryPlanFactory.class )
.createNativeQueryPlan( spec, factory );
queryPlanCache.putIfAbsent( spec, value ); queryPlanCache.putIfAbsent( spec, value );
} }
else { else {

View File

@ -0,0 +1,55 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.query.spi;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.service.Service;
import org.hibernate.service.spi.SessionFactoryServiceInitiator;
/**
* Contract for factories of query plans.
* <p>
* The default implementation creates query plans for SQL queries, but
* integrators can plug in another factory by registering a custom
* {@link SessionFactoryServiceInitiator} for this service contract.
*
* @author Gunnar Morling
*
*/
public interface QueryPlanFactory extends Service {
/**
* Creates a new query plan for the specified native query.
*
* @param nativeQuerySpecification
* Describes the query to create a plan for
* @param sessionFactory
* The current session factory
* @return A query plan for the specified native query.
*/
NativeSQLQueryPlan createNativeQueryPlan(
NativeSQLQuerySpecification nativeQuerySpecification,
SessionFactoryImplementor sessionFactory);
}

View File

@ -0,0 +1,55 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.query.spi;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceInitiator;
/**
* Initiates the default {@link QueryPlanFactory}.
*
* @author Gunnar Morling
*/
public class QueryPlanFactoryInitiator implements SessionFactoryServiceInitiator<QueryPlanFactory> {
public static final QueryPlanFactoryInitiator INSTANCE = new QueryPlanFactoryInitiator();
@Override
public QueryPlanFactory initiateService(SessionFactoryImplementor sessionFactory, Configuration configuration, ServiceRegistryImplementor registry) {
return new DefaultQueryPlanFactory();
}
@Override
public QueryPlanFactory initiateService(SessionFactoryImplementor sessionFactory, MetadataImplementor metadata, ServiceRegistryImplementor registry) {
return new DefaultQueryPlanFactory();
}
@Override
public Class<QueryPlanFactory> getServiceInitiated() {
return QueryPlanFactory.class;
}
}

View File

@ -28,6 +28,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.engine.query.spi.ParameterMetadataRecognizerInitiator; import org.hibernate.engine.query.spi.ParameterMetadataRecognizerInitiator;
import org.hibernate.engine.query.spi.QueryPlanFactoryInitiator;
import org.hibernate.engine.spi.CacheInitiator; import org.hibernate.engine.spi.CacheInitiator;
import org.hibernate.event.service.internal.EventListenerServiceInitiator; import org.hibernate.event.service.internal.EventListenerServiceInitiator;
import org.hibernate.service.spi.SessionFactoryServiceInitiator; import org.hibernate.service.spi.SessionFactoryServiceInitiator;
@ -49,6 +50,7 @@ public class StandardSessionFactoryServiceInitiators {
serviceInitiators.add( StatisticsInitiator.INSTANCE ); serviceInitiators.add( StatisticsInitiator.INSTANCE );
serviceInitiators.add( CacheInitiator.INSTANCE ); serviceInitiators.add( CacheInitiator.INSTANCE );
serviceInitiators.add( ParameterMetadataRecognizerInitiator.INSTANCE ); serviceInitiators.add( ParameterMetadataRecognizerInitiator.INSTANCE );
serviceInitiators.add( QueryPlanFactoryInitiator.INSTANCE );
return Collections.unmodifiableList( serviceInitiators ); return Collections.unmodifiableList( serviceInitiators );
} }