HHH-13715 - working support for "multi-table" HQL/Criteria UPDATE and DELETE queries

work on generalized CTE handling;
initial work on SQM CTE support
This commit is contained in:
Steve Ebersole 2019-11-12 14:19:23 -06:00
parent dd364ccf5f
commit eddd5b938b
51 changed files with 826 additions and 144 deletions

View File

@ -50,6 +50,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.ParsingException; import org.hibernate.query.sqm.ParsingException;
import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.SqmTreeCreationLogger; import org.hibernate.query.sqm.SqmTreeCreationLogger;
import org.hibernate.query.sqm.StrictJpaComplianceViolation; import org.hibernate.query.sqm.StrictJpaComplianceViolation;
import org.hibernate.query.sqm.UnknownEntityException; import org.hibernate.query.sqm.UnknownEntityException;
@ -131,9 +132,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.atn.PredictionMode;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static org.hibernate.query.hql.internal.HqlParser.IDENTIFIER; import static org.hibernate.query.hql.internal.HqlParser.IDENTIFIER;
@ -339,7 +338,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
final SqmDeleteStatement<?> deleteStatement = new SqmDeleteStatement<>( root, creationContext.getNodeBuilder() ); final SqmDeleteStatement<?> deleteStatement = new SqmDeleteStatement<>( root, SqmQuerySource.HQL, creationContext.getNodeBuilder() );
parameterCollector = deleteStatement; parameterCollector = deleteStatement;

View File

@ -34,12 +34,14 @@ import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
import org.hibernate.query.sqm.produce.function.SqmFunctionRegistry; import org.hibernate.query.sqm.produce.function.SqmFunctionRegistry;
import org.hibernate.query.sqm.spi.SqmCreationContext; import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslator; import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslator;
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslator;
import org.hibernate.query.sqm.sql.SqmInsertSelectTranslator; import org.hibernate.query.sqm.sql.SqmInsertSelectTranslator;
import org.hibernate.query.sqm.sql.SqmSelectTranslator; import org.hibernate.query.sqm.sql.SqmSelectTranslator;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory; import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.query.sqm.sql.internal.StandardSqmDeleteTranslator; import org.hibernate.query.sqm.sql.internal.StandardSqmDeleteTranslator;
import org.hibernate.query.sqm.sql.internal.StandardSqmInsertSelectTranslator; import org.hibernate.query.sqm.sql.internal.StandardSqmInsertSelectTranslator;
import org.hibernate.query.sqm.sql.internal.StandardSqmSelectTranslator; import org.hibernate.query.sqm.sql.internal.StandardSqmSelectTranslator;
import org.hibernate.query.sqm.sql.internal.StandardSqmUpdateTranslator;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationContext;
@ -193,6 +195,21 @@ public class QueryEngine {
domainParameterBindings domainParameterBindings
); );
} }
@Override
public SimpleSqmUpdateTranslator createSimpleUpdateTranslator(
QueryOptions queryOptions,
DomainParameterXref domainParameterXref,
QueryParameterBindings queryParameterBindings,
LoadQueryInfluencers loadQueryInfluencers,
SessionFactoryImplementor factory) {
return new StandardSqmUpdateTranslator(
factory,
queryOptions,
domainParameterXref,
queryParameterBindings
);
}
}; };
} }

View File

@ -7,6 +7,8 @@
package org.hibernate.query.sqm; package org.hibernate.query.sqm;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation; import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
@ -96,6 +98,10 @@ public interface SemanticQueryWalker<T> {
T visitSelectStatement(SqmSelectStatement<?> statement); T visitSelectStatement(SqmSelectStatement<?> statement);
T visitCteStatement(SqmCteStatement sqmCteStatement);
T visitCteConsumer(SqmCteConsumer consumer);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// from-clause / domain paths // from-clause / domain paths

View File

@ -1,33 +0,0 @@
/*
* 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.sqm.internal;
import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.sqm.mutation.spi.DeleteHandler;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.sql.exec.spi.ExecutionContext;
/**
* @author Steve Ebersole
*/
public class DeleteQueryPlanImpl implements NonSelectQueryPlan {
private final DeleteHandler deleteHandler;
private final ExecutionContext executionContext;
public DeleteQueryPlanImpl(
SqmDeleteStatement sqmDeleteStatement,
DeleteHandler deleteHandler,
ExecutionContext executionContext) {
this.deleteHandler = deleteHandler;
this.executionContext = executionContext;
}
@Override
public int executeUpdate(ExecutionContext executionContext) {
return deleteHandler.execute( this.executionContext );
}
}

View File

@ -47,7 +47,6 @@ import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.query.spi.SelectQueryPlan; import org.hibernate.query.spi.SelectQueryPlan;
import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.query.sqm.mutation.spi.UpdateHandler;
import org.hibernate.query.sqm.tree.SqmDmlStatement; import org.hibernate.query.sqm.tree.SqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
@ -562,13 +561,19 @@ public class QuerySqmImpl<R>
final String entityNameToUpdate = sqmStatement.getTarget().getReferencedPathSource().getHibernateEntityName(); final String entityNameToUpdate = sqmStatement.getTarget().getReferencedPathSource().getHibernateEntityName();
final EntityPersister entityDescriptor = getSessionFactory().getDomainModel().findEntityDescriptor( entityNameToUpdate ); final EntityPersister entityDescriptor = getSessionFactory().getDomainModel().findEntityDescriptor( entityNameToUpdate );
final UpdateHandler updateHandler = entityDescriptor.getSqmMultiTableMutationStrategy().buildUpdateHandler( final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy();
sqmStatement, if ( multiTableStrategy == null ) {
domainParameterXref, return new SimpleUpdateQueryPlan( sqmStatement, domainParameterXref );
this::getSessionFactory }
); else {
return new MultiTableUpdateQueryPlan(
return new UpdateQueryPlanImpl( sqmStatement, updateHandler, this ); multiTableStrategy.buildUpdateHandler(
sqmStatement,
domainParameterXref,
this::getSessionFactory
)
);
}
} }
@Override @Override

View File

@ -54,8 +54,8 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
if ( jdbcDelete == null ) { if ( jdbcDelete == null ) {
final QueryEngine queryEngine = factory.getQueryEngine(); final QueryEngine queryEngine = factory.getQueryEngine();
final SqmTranslatorFactory converterFactory = queryEngine.getSqmTranslatorFactory(); final SqmTranslatorFactory translatorFactory = queryEngine.getSqmTranslatorFactory();
final SimpleSqmDeleteTranslator converter = converterFactory.createSimpleDeleteTranslator( final SimpleSqmDeleteTranslator translator = translatorFactory.createSimpleDeleteTranslator(
executionContext.getQueryOptions(), executionContext.getQueryOptions(),
domainParameterXref, domainParameterXref,
executionContext.getQueryParameterBindings(), executionContext.getQueryParameterBindings(),
@ -63,7 +63,7 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan {
factory factory
); );
final SimpleSqmDeleteTranslation sqmInterpretation = converter.translate( sqmDelete ); final SimpleSqmDeleteTranslation sqmInterpretation = translator.translate( sqmDelete );
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory(); final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory();

View File

@ -6,25 +6,64 @@
*/ */
package org.hibernate.query.sqm.internal; package org.hibernate.query.sqm.internal;
import java.util.List;
import java.util.Map;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslation;
import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslator;
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslation;
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslator;
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameter;
import org.hibernate.sql.exec.spi.JdbcUpdate;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SimpleUpdateQueryPlan implements NonSelectQueryPlan { public class SimpleUpdateQueryPlan implements NonSelectQueryPlan {
private final SqmUpdateStatement sqmStatement; private final SqmUpdateStatement sqmUpdate;
private final DomainParameterXref domainParameterXref;
public SimpleUpdateQueryPlan(SqmUpdateStatement sqmStatement) { private JdbcUpdate jdbcUpdate;
this.sqmStatement = sqmStatement; private Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> jdbcParamsXref;
// todo (6.0) : here is where we need to perform the conversion into SQL AST public SimpleUpdateQueryPlan(
SqmUpdateStatement sqmUpdate,
DomainParameterXref domainParameterXref) {
this.sqmUpdate = sqmUpdate;
this.domainParameterXref = domainParameterXref;
} }
@Override @Override
public int executeUpdate(ExecutionContext executionContext) { public int executeUpdate(ExecutionContext executionContext) {
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
final JdbcServices jdbcServices = factory.getJdbcServices();
if ( jdbcUpdate == null ) {
final QueryEngine queryEngine = factory.getQueryEngine();
final SqmTranslatorFactory translatorFactory = queryEngine.getSqmTranslatorFactory();
final SimpleSqmUpdateTranslator translator = translatorFactory.createSimpleUpdateTranslator(
executionContext.getQueryOptions(),
domainParameterXref,
executionContext.getQueryParameterBindings(),
executionContext.getLoadQueryInfluencers(),
factory
);
final SimpleSqmUpdateTranslation sqmInterpretation = translator.translate( sqmUpdate );
}
throw new NotYetImplementedFor6Exception( ); throw new NotYetImplementedFor6Exception( );
} }

View File

@ -53,6 +53,7 @@ import org.hibernate.query.internal.QueryHelper;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.SemanticException; import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.produce.function.SqmFunctionTemplate; import org.hibernate.query.sqm.produce.function.SqmFunctionTemplate;
import org.hibernate.query.sqm.function.SqmCastTarget; import org.hibernate.query.sqm.function.SqmCastTarget;
import org.hibernate.query.sqm.function.SqmDistinct; import org.hibernate.query.sqm.function.SqmDistinct;
@ -174,7 +175,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder {
@Override @Override
public <T> SqmDeleteStatement<T> createCriteriaDelete(Class<T> targetEntity) { public <T> SqmDeleteStatement<T> createCriteriaDelete(Class<T> targetEntity) {
return new SqmDeleteStatement<>( targetEntity, this ); return new SqmDeleteStatement<>( targetEntity, SqmQuerySource.CRITERIA, this );
} }
@Override @Override

View File

@ -12,6 +12,8 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.QueryLogger; import org.hibernate.query.QueryLogger;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation; import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
@ -284,6 +286,20 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
return null; return null;
} }
@Override
public Object visitCteStatement(SqmCteStatement sqmCteStatement) {
if ( DEBUG_ENABLED ) {
logIndented( "cte" );
}
return null;
}
@Override
public Object visitCteConsumer(SqmCteConsumer consumer) {
return null;
}
@Override @Override
public Object visitUpdateStatement(SqmUpdateStatement<?> statement) { public Object visitUpdateStatement(SqmUpdateStatement<?> statement) {
if ( DEBUG_ENABLED ) { if ( DEBUG_ENABLED ) {

View File

@ -120,7 +120,7 @@ public class CteBasedMutationStrategy implements SqmMultiTableMutationStrategy {
); );
} }
this.cteTable = new CteTable( rootDescriptor, runtimeModelCreationContext ); this.cteTable = new CteTable( rootDescriptor, runtimeModelCreationContext.getTypeConfiguration() );
} }
@Override @Override

View File

@ -81,6 +81,7 @@ public class CteDeleteHandler extends AbstractCteMutationHandler implements Dele
final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( getDomainParameterXref().getQueryParameterCount() ); final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( getDomainParameterXref().getQueryParameterCount() );
final QuerySpec cteDefinitionQuerySpec = getCteTable().createCteDefinition( final QuerySpec cteDefinitionQuerySpec = getCteTable().createCteDefinition(
ids, ids,
getEntityDescriptor().getIdentifierMapping(),
jdbcParameterBindings, jdbcParameterBindings,
executionContext executionContext
); );

View File

@ -14,6 +14,8 @@ import org.hibernate.query.sqm.function.SqmExtractUnit;
import org.hibernate.query.sqm.function.SqmFunction; import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.function.SqmStar; import org.hibernate.query.sqm.function.SqmStar;
import org.hibernate.query.sqm.function.SqmTrimSpecification; import org.hibernate.query.sqm.function.SqmTrimSpecification;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation; import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
@ -141,6 +143,33 @@ public class BaseSemanticQueryWalker implements SemanticQueryWalker<Object> {
return statement; return statement;
} }
@Override
public Object visitCteStatement(SqmCteStatement sqmCteStatement) {
visitCteConsumer( sqmCteStatement.getCteConsumer() );
return sqmCteStatement;
}
@Override
public Object visitCteConsumer(SqmCteConsumer consumer) {
if ( consumer instanceof SqmQuerySpec ) {
return visitQuerySpec( ( (SqmQuerySpec) consumer ) );
}
if ( consumer instanceof SqmDeleteStatement ) {
return visitDeleteStatement( ( (SqmDeleteStatement) consumer ) );
}
if ( consumer instanceof SqmUpdateStatement ) {
visitUpdateStatement( (SqmUpdateStatement) consumer );
}
if ( consumer instanceof SqmInsertSelectStatement ) {
visitInsertSelectStatement( (SqmInsertSelectStatement) consumer );
}
throw new UnsupportedOperationException( "Unsupported SqmCteConsumer : " + consumer );
}
@Override @Override
public Object visitQuerySpec(SqmQuerySpec querySpec) { public Object visitQuerySpec(SqmQuerySpec querySpec) {
visitFromClause( querySpec.getFromClause() ); visitFromClause( querySpec.getFromClause() );

View File

@ -11,7 +11,6 @@ import java.util.Collections;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -46,6 +45,10 @@ import org.hibernate.query.sqm.sql.internal.EmbeddableValuedPathInterpretation;
import org.hibernate.query.sqm.sql.internal.SqlAstQuerySpecProcessingStateImpl; import org.hibernate.query.sqm.sql.internal.SqlAstQuerySpecProcessingStateImpl;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation; import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation; import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.cte.SqmCteTable;
import org.hibernate.query.sqm.tree.cte.SqmCteTableColumn;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
@ -102,6 +105,10 @@ import org.hibernate.sql.ast.spi.SqlAstProcessingState;
import org.hibernate.sql.ast.spi.SqlAstQuerySpecProcessingState; import org.hibernate.sql.ast.spi.SqlAstQuerySpecProcessingState;
import org.hibernate.sql.ast.spi.SqlAstTreeHelper; import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.cte.CteColumn;
import org.hibernate.sql.ast.tree.cte.CteConsumer;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.cte.CteTable;
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression; import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
@ -269,6 +276,44 @@ public abstract class BaseSqmToSqlAstConverter
throw new AssertionFailure( "SelectStatement not supported" ); throw new AssertionFailure( "SelectStatement not supported" );
} }
@Override
public CteStatement visitCteStatement(SqmCteStatement sqmCteStatement) {
final CteTable cteTable = createCteTable( sqmCteStatement );
return new CteStatement(
visitQuerySpec( sqmCteStatement.getCteDefinition() ),
sqmCteStatement.getCteLabel(),
cteTable,
visitCteConsumer( sqmCteStatement.getCteConsumer() )
);
}
protected CteTable createCteTable(SqmCteStatement sqmCteStatement) {
final SqmCteTable sqmCteTable = sqmCteStatement.getCteTable();
final List<SqmCteTableColumn> sqmCteColumns = sqmCteTable.getColumns();
final List<CteColumn> sqlCteColumns = new ArrayList<>( sqmCteColumns.size() );
for ( int i = 0; i < sqmCteColumns.size(); i++ ) {
final SqmCteTableColumn sqmCteTableColumn = sqmCteColumns.get( i );
sqlCteColumns.add(
new CteColumn(
sqmCteTableColumn.getColumnName(),
sqmCteTableColumn.getType()
)
);
}
return new CteTable(
sqlCteColumns,
getCreationContext().getSessionFactory()
);
}
@Override
public CteConsumer visitCteConsumer(SqmCteConsumer consumer) {
return (CteConsumer) super.visitCteConsumer( consumer );
}
@Override @Override
public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) { public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) {

View File

@ -12,6 +12,6 @@ import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface SimpleSqmDeleteTranslator extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess { public interface SimpleSqmDeleteTranslator extends SqmTranslator, SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess {
SimpleSqmDeleteTranslation translate(SqmDeleteStatement statement); SimpleSqmDeleteTranslation translate(SqmDeleteStatement statement);
} }

View File

@ -0,0 +1,40 @@
/*
* 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.sqm.sql;
import java.util.List;
import java.util.Map;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
import org.hibernate.sql.ast.tree.update.UpdateStatement;
import org.hibernate.sql.exec.spi.JdbcParameter;
/**
* @author Steve Ebersole
*/
public class SimpleSqmUpdateTranslation implements SqmTranslation {
private final UpdateStatement sqlAst;
private final Map<SqmParameter, List<JdbcParameter>> jdbcParamMap;
public SimpleSqmUpdateTranslation(
UpdateStatement sqlAst,
Map<SqmParameter, List<JdbcParameter>> jdbcParamMap) {
this.sqlAst = sqlAst;
this.jdbcParamMap = jdbcParamMap;
}
@Override
public UpdateStatement getSqlAst() {
return sqlAst;
}
@Override
public Map<SqmParameter, List<JdbcParameter>> getJdbcParamsBySqmParam() {
return jdbcParamMap;
}
}

View File

@ -0,0 +1,17 @@
/*
* 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.sqm.sql;
import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
/**
* @author Steve Ebersole
*/
public interface SimpleSqmUpdateTranslator extends SqmTranslator, SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess {
SimpleSqmUpdateTranslation translate(SqmUpdateStatement sqmUpdate);
}

View File

@ -12,6 +12,6 @@ import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface SqmInsertSelectTranslator extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess { public interface SqmInsertSelectTranslator extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, SqmTranslator {
SqmInsertSelectTranslation translate(SqmInsertSelectStatement statement); SqmInsertSelectTranslation translate(SqmInsertSelectStatement statement);
} }

View File

@ -13,7 +13,7 @@ import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface SqmSelectTranslator extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess { public interface SqmSelectTranslator extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, SqmTranslator {
SqmSelectTranslation translate(SqmSelectStatement sqmStatement); SqmSelectTranslation translate(SqmSelectStatement sqmStatement);
SqmQuerySpecTranslation translate(SqmQuerySpec sqmQuerySpec); SqmQuerySpecTranslation translate(SqmQuerySpec sqmQuerySpec);
} }

View File

@ -0,0 +1,17 @@
/*
* 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.sqm.sql;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.sql.ast.tree.cte.CteStatement;
/**
* @author Steve Ebersole
*/
public interface SqmTranslator {
CteStatement translate(SqmCteStatement sqmCte);
}

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.sql; package org.hibernate.query.sqm.sql;
import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.internal.DomainParameterXref;
@ -38,5 +39,13 @@ public interface SqmTranslatorFactory {
LoadQueryInfluencers influencers, LoadQueryInfluencers influencers,
SqlAstCreationContext creationContext); SqlAstCreationContext creationContext);
SimpleSqmUpdateTranslator createSimpleUpdateTranslator(
QueryOptions queryOptions,
DomainParameterXref domainParameterXref,
QueryParameterBindings queryParameterBindings,
LoadQueryInfluencers loadQueryInfluencers,
SessionFactoryImplementor factory);
// todo (6.0) : update, delete, etc converters... // todo (6.0) : update, delete, etc converters...
} }

View File

@ -17,12 +17,14 @@ import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter; import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslation; import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslation;
import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslator; import org.hibernate.query.sqm.sql.SimpleSqmDeleteTranslator;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.JoinType; import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstTreeHelper; import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.delete.DeleteStatement; import org.hibernate.sql.ast.tree.delete.DeleteStatement;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.predicate.Predicate;
@ -111,4 +113,10 @@ public class StandardSqmDeleteTranslator
getProcessingStateStack().pop(); getProcessingStateStack().pop();
} }
} }
@Override
public CteStatement translate(SqmCteStatement sqmCte) {
visitCteStatement( sqmCte );
return null;
}
} }

View File

@ -16,9 +16,11 @@ import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter; import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SqmInsertSelectTranslation; import org.hibernate.query.sqm.sql.SqmInsertSelectTranslation;
import org.hibernate.query.sqm.sql.SqmInsertSelectTranslator; import org.hibernate.query.sqm.sql.SqmInsertSelectTranslator;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.sql.ast.JoinType; import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
@ -41,6 +43,11 @@ public class StandardSqmInsertSelectTranslator
return new SqmInsertSelectTranslation( visitInsertSelectStatement( sqmStatement ), getJdbcParamsBySqmParam() ); return new SqmInsertSelectTranslation( visitInsertSelectStatement( sqmStatement ), getJdbcParamsBySqmParam() );
} }
@Override
public CteStatement translate(SqmCteStatement sqmCte) {
return visitCteStatement( sqmCte );
}
@Override @Override
public InsertSelectStatement visitInsertSelectStatement(SqmInsertSelectStatement sqmStatement) { public InsertSelectStatement visitInsertSelectStatement(SqmInsertSelectStatement sqmStatement) {
final InsertSelectStatement insertSelectStatement = new InsertSelectStatement(); final InsertSelectStatement insertSelectStatement = new InsertSelectStatement();

View File

@ -33,6 +33,7 @@ import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SqmQuerySpecTranslation; import org.hibernate.query.sqm.sql.SqmQuerySpecTranslation;
import org.hibernate.query.sqm.sql.SqmSelectTranslation; import org.hibernate.query.sqm.sql.SqmSelectTranslation;
import org.hibernate.query.sqm.sql.SqmSelectTranslator; import org.hibernate.query.sqm.sql.SqmSelectTranslator;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
@ -45,6 +46,7 @@ import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral; import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
@ -433,6 +435,11 @@ public class StandardSqmSelectTranslator
// .getOrMakeJavaDescriptor( namedClass ); // .getOrMakeJavaDescriptor( namedClass );
} }
@Override
public CteStatement translate(SqmCteStatement sqmCte) {
return visitCteStatement( sqmCte );
}
// @Override // @Override
// public SqlSelection resolveSqlSelection(Expression expression) { // public SqlSelection resolveSqlSelection(Expression expression) {

View File

@ -0,0 +1,151 @@
/*
* 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.sqm.sql.internal;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslation;
import org.hibernate.query.sqm.sql.SimpleSqmUpdateTranslator;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.update.SqmAssignment;
import org.hibernate.query.sqm.tree.update.SqmSetClause;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.update.Assignment;
import org.hibernate.sql.ast.tree.update.UpdateStatement;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.exec.spi.JdbcParameter;
/**
* @author Steve Ebersole
*/
public class StandardSqmUpdateTranslator
extends BaseSqmToSqlAstConverter
implements SimpleSqmUpdateTranslator {
public StandardSqmUpdateTranslator(
SqlAstCreationContext creationContext,
QueryOptions queryOptions,
DomainParameterXref domainParameterXref,
QueryParameterBindings domainParameterBindings) {
super( creationContext, queryOptions, domainParameterXref, domainParameterBindings );
}
@Override
public SimpleSqmUpdateTranslation translate(SqmUpdateStatement sqmUpdate) {
final UpdateStatement sqlUpdateAst = visitUpdateStatement( sqmUpdate );
return new SimpleSqmUpdateTranslation(
sqlUpdateAst,
getJdbcParamsBySqmParam()
);
}
@Override
public UpdateStatement visitUpdateStatement(SqmUpdateStatement sqmStatement) {
final String entityName = sqmStatement.getTarget().getEntityName();
final EntityPersister entityDescriptor = getCreationContext().getDomainModel().getEntityDescriptor( entityName );
assert entityDescriptor != null;
getProcessingStateStack().push(
new SqlAstProcessingStateImpl(
null,
this,
getCurrentClauseStack()::getCurrent
)
);
try {
final NavigablePath rootPath = new NavigablePath( entityName );
final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup(
rootPath,
null,
JoinType.LEFT,
LockMode.WRITE,
stem -> getSqlAliasBaseGenerator().createSqlAliasBase( stem ),
getSqlExpressionResolver(),
() -> predicate -> additionalRestrictions = predicate,
getCreationContext()
);
getFromClauseIndex().registerTableGroup( rootPath, rootTableGroup );
if ( ! rootTableGroup.getTableReferenceJoins().isEmpty() ) {
throw new HibernateException( "Not expecting multiple table references for an SQM DELETE" );
}
Predicate suppliedPredicate = null;
final SqmWhereClause whereClause = sqmStatement.getWhereClause();
if ( whereClause != null && whereClause.getPredicate() != null ) {
getCurrentClauseStack().push( Clause.WHERE );
try {
suppliedPredicate = (Predicate) whereClause.getPredicate().accept( this );
}
finally {
getCurrentClauseStack().pop();
}
}
return new UpdateStatement(
rootTableGroup.getPrimaryTableReference(),
visitSetClause( sqmStatement.getSetClause() ),
SqlAstTreeHelper.combinePredicates( suppliedPredicate, additionalRestrictions )
);
}
finally {
getProcessingStateStack().pop();
}
}
@Override
public List<Assignment> visitSetClause(SqmSetClause setClause) {
final List<Assignment> assignments = new ArrayList<>();
for ( SqmAssignment sqmAssignment : setClause.getAssignments() ) {
final SqmPathInterpretation assignedPathInterpretation = (SqmPathInterpretation) sqmAssignment.getTargetPath().accept( this );
assignedPathInterpretation.getExpressionType().visitColumns(
(columnExpression, containingTableExpression, jdbcMapping) -> {
final JdbcParameter jdbcParameter = new JdbcParameterImpl( jdbcMapping );
assignments.add(
new Assignment(
new ColumnReference(
containingTableExpression,
columnExpression,
jdbcMapping,
getCreationContext().getSessionFactory()
),
jdbcParameter
)
);
}
);
}
return assignments;
}
@Override
public CteStatement translate(SqmCteStatement sqmCte) {
return visitCteStatement( sqmCte );
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.tree; package org.hibernate.query.sqm.tree;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.select.SqmSubQuery; import org.hibernate.query.sqm.tree.select.SqmSubQuery;
@ -18,12 +19,12 @@ public abstract class AbstractSqmDmlStatement<E>
implements SqmDmlStatement<E> { implements SqmDmlStatement<E> {
private SqmRoot<E> target; private SqmRoot<E> target;
public AbstractSqmDmlStatement(NodeBuilder nodeBuilder) { public AbstractSqmDmlStatement(SqmQuerySource querySource, NodeBuilder nodeBuilder) {
super( nodeBuilder ); super( querySource, nodeBuilder );
} }
public AbstractSqmDmlStatement(SqmRoot<E> target, NodeBuilder nodeBuilder) { public AbstractSqmDmlStatement(SqmRoot<E> target, SqmQuerySource querySource, NodeBuilder nodeBuilder) {
this( nodeBuilder ); this( querySource, nodeBuilder );
this.target = target; this.target = target;
} }

View File

@ -13,6 +13,7 @@ import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter; import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper; import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.expression.SqmParameter;
@ -22,12 +23,22 @@ import org.hibernate.query.sqm.internal.ParameterCollector;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractSqmStatement<T> extends AbstractSqmNode implements SqmStatement<T>, ParameterCollector { public abstract class AbstractSqmStatement<T> extends AbstractSqmNode implements SqmStatement<T>, ParameterCollector {
public AbstractSqmStatement(NodeBuilder builder) { private final SqmQuerySource querySource;
public AbstractSqmStatement(
SqmQuerySource querySource,
NodeBuilder builder) {
super( builder ); super( builder );
this.querySource = querySource;
} }
private Set<SqmParameter<?>> parameters; private Set<SqmParameter<?>> parameters;
@Override
public SqmQuerySource getQuerySource() {
return querySource;
}
@Override @Override
public void addParameter(SqmParameter parameter) { public void addParameter(SqmParameter parameter) {
if ( parameters == null ) { if ( parameters == null ) {

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.tree; package org.hibernate.query.sqm.tree;
import org.hibernate.query.criteria.JpaManipulationCriteria; import org.hibernate.query.criteria.JpaManipulationCriteria;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -18,7 +19,7 @@ import org.hibernate.query.sqm.tree.from.SqmRoot;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface SqmDmlStatement<E> extends SqmStatement<E>, JpaManipulationCriteria<E> { public interface SqmDmlStatement<E> extends SqmStatement<E>, SqmCteConsumer, JpaManipulationCriteria<E> {
/** /**
* Get the root path that is the target of the DML statement. * Get the root path that is the target of the DML statement.
*/ */

View File

@ -0,0 +1,15 @@
/*
* 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.sqm.tree.cte;
import org.hibernate.query.sqm.tree.SqmNode;
/**
* @author Steve Ebersole
*/
public interface SqmCteConsumer extends SqmNode {
}

View File

@ -0,0 +1,76 @@
/*
* 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.sqm.tree.cte;
import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.criteria.JpaSubQuery;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.AbstractSqmStatement;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
/**
* @author Steve Ebersole
*/
public class SqmCteStatement extends AbstractSqmStatement implements SqmStatement {
private final SqmCteTable cteTable;
private final String cteLabel;
private final SqmQuerySpec cteDefinition;
private final SqmCteConsumer cteConsumer;
public SqmCteStatement(
SqmCteTable cteTable,
String cteLabel,
SqmQuerySpec cteDefinition,
SqmCteConsumer cteConsumer,
SqmQuerySource querySource,
NodeBuilder nodeBuilder) {
super( querySource, nodeBuilder );
this.cteTable = cteTable;
this.cteLabel = cteLabel;
this.cteDefinition = cteDefinition;
this.cteConsumer = cteConsumer;
}
public SqmCteTable getCteTable() {
return cteTable;
}
public String getCteLabel() {
return cteLabel;
}
public SqmQuerySpec getCteDefinition() {
return cteDefinition;
}
public SqmCteConsumer getCteConsumer() {
return cteConsumer;
}
@Override
public <U> JpaSubQuery<U> subquery(Class<U> type) {
return new SqmSubQuery<U>(
this,
new SqmQuerySpec<>( nodeBuilder() ),
nodeBuilder()
);
}
@Override
public JpaPredicate getRestriction() {
return null;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitCteStatement( this );
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.sqm.tree.cte;
import java.util.List;
import java.util.function.Consumer;
/**
* @author Steve Ebersole
*/
public class SqmCteTable {
private final String cteName;
private final List<SqmCteTableColumn> columns;
public SqmCteTable(String cteName, List<SqmCteTableColumn> columns) {
this.cteName = cteName;
this.columns = columns;
}
public String getCteName() {
return cteName;
}
public List<SqmCteTableColumn> getColumns() {
return columns;
}
public void visitColumns(Consumer<SqmCteTableColumn> columnConsumer) {
for ( int i = 0; i < columns.size(); i++ ) {
columnConsumer.accept( columns.get( i ) );
}
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.sqm.tree.cte;
import org.hibernate.type.BasicType;
/**
* @author Steve Ebersole
*/
public class SqmCteTableColumn {
private final SqmCteTable cteTable;
private final String columnName;
private final BasicType typeExpressable;
private final boolean allowNulls;
public SqmCteTableColumn(
SqmCteTable cteTable,
String columnName,
BasicType typeExpressable,
boolean allowNulls) {
this.cteTable = cteTable;
this.columnName = columnName;
this.typeExpressable = typeExpressable;
this.allowNulls = allowNulls;
}
public SqmCteTable getCteTable() {
return cteTable;
}
public String getColumnName() {
return columnName;
}
public BasicType getType() {
return typeExpressable;
}
public boolean isAllowNulls() {
return allowNulls;
}
}

View File

@ -15,38 +15,39 @@ import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.criteria.JpaCriteriaDelete; import org.hibernate.query.criteria.JpaCriteriaDelete;
import org.hibernate.query.criteria.JpaPredicate; import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement; import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement; import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SqmDeleteStatement<T> public class SqmDeleteStatement<T>
extends AbstractSqmDmlStatement<T> extends AbstractSqmDmlStatement<T>
implements SqmDeleteOrUpdateStatement<T>, JpaCriteriaDelete<T> { implements SqmDeleteOrUpdateStatement<T>, SqmCteConsumer, JpaCriteriaDelete<T> {
private final SqmQuerySource querySource; private final SqmQuerySource querySource;
private SqmWhereClause whereClause; private SqmWhereClause whereClause;
public SqmDeleteStatement(SqmRoot<T> target, NodeBuilder nodeBuilder) { public SqmDeleteStatement(SqmRoot<T> target, SqmQuerySource querySource, NodeBuilder nodeBuilder) {
super( target, nodeBuilder ); super( target, querySource, nodeBuilder );
this.querySource = SqmQuerySource.HQL; this.querySource = SqmQuerySource.HQL;
} }
public SqmDeleteStatement(Class<T> targetEntity, NodeBuilder nodeBuilder) { public SqmDeleteStatement(Class<T> targetEntity, SqmQuerySource querySource, NodeBuilder nodeBuilder) {
super( super(
new SqmRoot<>( new SqmRoot<>(
nodeBuilder.getDomainModel().entity( targetEntity ), nodeBuilder.getDomainModel().entity( targetEntity ),
null, null,
nodeBuilder nodeBuilder
), ),
querySource,
nodeBuilder nodeBuilder
); );
this.querySource = SqmQuerySource.CRITERIA; this.querySource = SqmQuerySource.CRITERIA;

View File

@ -12,6 +12,7 @@ import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement; import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement;
import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -24,12 +25,12 @@ import org.hibernate.query.sqm.tree.from.SqmRoot;
public abstract class AbstractSqmInsertStatement<T> extends AbstractSqmDmlStatement<T> implements SqmInsertStatement<T> { public abstract class AbstractSqmInsertStatement<T> extends AbstractSqmDmlStatement<T> implements SqmInsertStatement<T> {
private List<SqmPath> insertionTargetPaths; private List<SqmPath> insertionTargetPaths;
protected AbstractSqmInsertStatement(NodeBuilder nodeBuilder) { protected AbstractSqmInsertStatement(SqmQuerySource querySource, NodeBuilder nodeBuilder) {
super( nodeBuilder ); super( querySource, nodeBuilder );
} }
protected AbstractSqmInsertStatement(SqmRoot<T> targetRoot, NodeBuilder nodeBuilder) { protected AbstractSqmInsertStatement(SqmRoot<T> targetRoot, SqmQuerySource querySource, NodeBuilder nodeBuilder) {
super( targetRoot, nodeBuilder ); super( targetRoot, querySource, nodeBuilder );
} }
@Override @Override

View File

@ -18,13 +18,10 @@ import org.hibernate.query.sqm.tree.from.SqmRoot;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> implements JpaCriteriaInsertSelect<T> { public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> implements JpaCriteriaInsertSelect<T> {
private final SqmQuerySource querySource;
private SqmQuerySpec selectQuerySpec; private SqmQuerySpec selectQuerySpec;
public SqmInsertSelectStatement(SqmRoot<T> targetRoot, NodeBuilder nodeBuilder) { public SqmInsertSelectStatement(SqmRoot<T> targetRoot, NodeBuilder nodeBuilder) {
super( targetRoot, nodeBuilder ); super( targetRoot, SqmQuerySource.HQL, nodeBuilder );
querySource = SqmQuerySource.HQL;
} }
public SqmInsertSelectStatement(Class<T> targetEntity, NodeBuilder nodeBuilder) { public SqmInsertSelectStatement(Class<T> targetEntity, NodeBuilder nodeBuilder) {
@ -34,9 +31,9 @@ public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> i
null, null,
nodeBuilder nodeBuilder
), ),
SqmQuerySource.CRITERIA,
nodeBuilder nodeBuilder
); );
querySource = SqmQuerySource.CRITERIA;
} }
public SqmQuerySpec getSelectQuerySpec() { public SqmQuerySpec getSelectQuerySpec() {
@ -52,11 +49,6 @@ public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> i
return walker.visitInsertSelectStatement( this ); return walker.visitInsertSelectStatement( this );
} }
@Override
public SqmQuerySource getQuerySource() {
return querySource;
}
@Override @Override
public JpaPredicate getRestriction() { public JpaPredicate getRestriction() {
// insert has no predicate // insert has no predicate

View File

@ -28,12 +28,9 @@ import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
public abstract class AbstractSqmSelectQuery<T> public abstract class AbstractSqmSelectQuery<T>
extends AbstractSqmNode extends AbstractSqmNode
implements SqmSelectQuery<T> { implements SqmSelectQuery<T> {
private SqmQuerySpec<T> sqmQuerySpec; private SqmQuerySpec<T> sqmQuerySpec;
private Class resultType; private Class resultType;
@SuppressWarnings("WeakerAccess")
public AbstractSqmSelectQuery(Class<T> resultType, NodeBuilder builder) { public AbstractSqmSelectQuery(Class<T> resultType, NodeBuilder builder) {
super( builder ); super( builder );
this.sqmQuerySpec = new SqmQuerySpec( builder ); this.sqmQuerySpec = new SqmQuerySpec( builder );
@ -41,14 +38,10 @@ public abstract class AbstractSqmSelectQuery<T>
} }
@SuppressWarnings("WeakerAccess")
public AbstractSqmSelectQuery(SqmQuerySpec<T> sqmQuerySpec, NodeBuilder builder) { public AbstractSqmSelectQuery(SqmQuerySpec<T> sqmQuerySpec, NodeBuilder builder) {
super( builder ); this( (Class) sqmQuerySpec.getSelectClause().getJavaType(), builder );
this.sqmQuerySpec = sqmQuerySpec;
this.resultType = sqmQuerySpec.getSelectClause().getJavaType();
} }
@Override @Override
public Class getResultType() { public Class getResultType() {
return resultType; return resultType;

View File

@ -22,6 +22,7 @@ import org.hibernate.query.criteria.JpaRoot;
import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.tree.SqmNode; import org.hibernate.query.sqm.tree.SqmNode;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.from.SqmFromClause; import org.hibernate.query.sqm.tree.from.SqmFromClause;
import org.hibernate.query.sqm.tree.from.SqmFromClauseContainer; import org.hibernate.query.sqm.tree.from.SqmFromClauseContainer;
@ -36,7 +37,7 @@ import org.hibernate.type.StandardBasicTypes;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SqmQuerySpec<T> implements SqmNode, SqmFromClauseContainer, SqmWhereClauseContainer, JpaQueryStructure<T> { public class SqmQuerySpec<T> implements SqmCteConsumer, SqmNode, SqmFromClauseContainer, SqmWhereClauseContainer, JpaQueryStructure<T> {
private final NodeBuilder nodeBuilder; private final NodeBuilder nodeBuilder;
private SqmFromClause fromClause; private SqmFromClause fromClause;

View File

@ -18,11 +18,12 @@ import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.criteria.JpaCriteriaUpdate; import org.hibernate.query.criteria.JpaCriteriaUpdate;
import org.hibernate.query.criteria.JpaPredicate; import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.internal.SqmCriteriaNodeBuilder;
import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement; import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement; import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement;
import org.hibernate.query.sqm.tree.cte.SqmCteConsumer;
import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
@ -32,9 +33,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
*/ */
public class SqmUpdateStatement<T> public class SqmUpdateStatement<T>
extends AbstractSqmDmlStatement<T> extends AbstractSqmDmlStatement<T>
implements SqmDeleteOrUpdateStatement<T>, JpaCriteriaUpdate<T> { implements SqmDeleteOrUpdateStatement<T>, SqmCteConsumer, JpaCriteriaUpdate<T> {
private final SqmQuerySource querySource;
private SqmSetClause setClause; private SqmSetClause setClause;
private SqmWhereClause whereClause; private SqmWhereClause whereClause;
@ -43,8 +42,7 @@ public class SqmUpdateStatement<T>
} }
public SqmUpdateStatement(SqmRoot<T> target, SqmQuerySource querySource, NodeBuilder nodeBuilder) { public SqmUpdateStatement(SqmRoot<T> target, SqmQuerySource querySource, NodeBuilder nodeBuilder) {
super( target, nodeBuilder ); super( target, querySource, nodeBuilder );
this.querySource = querySource;
} }
public SqmUpdateStatement(Class<T> targetEntity, SqmCriteriaNodeBuilder nodeBuilder) { public SqmUpdateStatement(Class<T> targetEntity, SqmCriteriaNodeBuilder nodeBuilder) {
@ -59,11 +57,6 @@ public class SqmUpdateStatement<T>
); );
} }
@Override
public SqmQuerySource getQuerySource() {
return querySource;
}
public SqmSetClause getSetClause() { public SqmSetClause getSetClause() {
return setClause; return setClause;
} }

View File

@ -9,14 +9,14 @@ package org.hibernate.sql.ast.spi;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.ast.SqlAstInsertSelectTranslator; import org.hibernate.sql.ast.SqlAstInsertSelectTranslator;
import org.hibernate.sql.ast.tree.cte.CteColumn;
import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
import org.hibernate.sql.exec.spi.JdbcInsert; import org.hibernate.sql.exec.spi.JdbcInsert;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.sql.exec.spi.JdbcParameterBinder; import org.hibernate.sql.exec.spi.JdbcParameterBinder;
/** /**
@ -81,7 +81,46 @@ public class StandardSqlAstInsertSelectTranslator
} }
@Override @Override
public JdbcOperation translate(CteStatement cteStatement) { public JdbcInsert translate(CteStatement sqlAst) {
throw new NotYetImplementedFor6Exception( getClass() ); assert sqlAst.getCteConsumer() instanceof DeleteStatement;
appendSql( "with " );
appendSql( sqlAst.getCteLabel() );
appendSql( " (" );
String separator = "";
for ( int i = 0; i < sqlAst.getCteTable().getCteColumns().size(); i++ ) {
final CteColumn cteColumn = sqlAst.getCteTable().getCteColumns().get( i );
appendSql( separator );
appendSql( cteColumn.getColumnExpression() );
separator = ", ";
}
appendSql( ") as (" );
visitQuerySpec( sqlAst.getCteDefinition() );
appendSql( ") " );
translate( (InsertSelectStatement) sqlAst.getCteConsumer() );
return new JdbcInsert() {
@Override
public String getSql() {
return StandardSqlAstInsertSelectTranslator.this.getSql();
}
@Override
public List<JdbcParameterBinder> getParameterBinders() {
return StandardSqlAstInsertSelectTranslator.this.getParameterBinders();
}
@Override
public Set<String> getAffectedTableNames() {
return StandardSqlAstInsertSelectTranslator.this.getAffectedTableNames();
}
};
} }
} }

View File

@ -13,10 +13,10 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.ast.SqlAstSelectTranslator; import org.hibernate.sql.ast.SqlAstSelectTranslator;
import org.hibernate.sql.ast.SqlTreePrinter; import org.hibernate.sql.ast.SqlTreePrinter;
import org.hibernate.sql.ast.tree.SqlAstTreeLogger; import org.hibernate.sql.ast.tree.SqlAstTreeLogger;
import org.hibernate.sql.ast.tree.cte.CteColumn;
import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.sql.exec.spi.JdbcSelect; import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.internal.JdbcValuesMappingProducerStandard; import org.hibernate.sql.results.internal.JdbcValuesMappingProducerStandard;
@ -36,7 +36,31 @@ public class StandardSqlAstSelectTranslator
} }
@Override @Override
public JdbcSelect translate(CteStatement cteStatement) { public JdbcSelect translate(CteStatement sqlAst) {
assert sqlAst.getCteConsumer() instanceof QuerySpec;
appendSql( "with " );
appendSql( sqlAst.getCteLabel() );
appendSql( " (" );
String separator = "";
for ( int i = 0; i < sqlAst.getCteTable().getCteColumns().size(); i++ ) {
final CteColumn cteColumn = sqlAst.getCteTable().getCteColumns().get( i );
appendSql( separator );
appendSql( cteColumn.getColumnExpression() );
separator = ", ";
}
appendSql( ") as (" );
visitQuerySpec( sqlAst.getCteDefinition() );
appendSql( ") " );
translate( (QuerySpec) sqlAst.getCteConsumer() );
throw new NotYetImplementedFor6Exception( getClass() ); throw new NotYetImplementedFor6Exception( getClass() );
} }

View File

@ -7,26 +7,21 @@
package org.hibernate.sql.ast.tree.cte; package org.hibernate.sql.ast.tree.cte;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.sql.ast.tree.cte.CteTable;
/** /**
* Information about a column in the CTE table
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class CteColumn { public class CteColumn {
private final CteTable cteTable;
private final String columnExpression; private final String columnExpression;
private final JdbcMapping jdbcMapping; private final JdbcMapping jdbcMapping;
public CteColumn(CteTable cteTable, String columnExpression, JdbcMapping jdbcMapping) { public CteColumn(String columnExpression, JdbcMapping jdbcMapping) {
this.cteTable = cteTable;
this.columnExpression = columnExpression; this.columnExpression = columnExpression;
this.jdbcMapping = jdbcMapping; this.jdbcMapping = jdbcMapping;
} }
public CteTable getCteTable() {
return cteTable;
}
public String getColumnExpression() { public String getColumnExpression() {
return columnExpression; return columnExpression;
} }

View File

@ -0,0 +1,16 @@
/*
* 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.sql.ast.tree.cte;
/**
* The consumer part of a CTE statement - the select or insert or delete or update that uses
* the CTE
*
* @author Steve Ebersole
*/
public interface CteConsumer {
}

View File

@ -18,9 +18,9 @@ public class CteStatement implements Statement {
private final String cteLabel; private final String cteLabel;
private final CteTable cteTable; private final CteTable cteTable;
private final QuerySpec cteDefinition; private final QuerySpec cteDefinition;
private final Statement cteConsumer; private final CteConsumer cteConsumer;
public CteStatement(QuerySpec cteDefinition, String cteLabel, CteTable cteTable, Statement cteConsumer) { public CteStatement(QuerySpec cteDefinition, String cteLabel, CteTable cteTable, CteConsumer cteConsumer) {
this.cteDefinition = cteDefinition; this.cteDefinition = cteDefinition;
this.cteLabel = cteLabel; this.cteLabel = cteLabel;
this.cteTable = cteTable; this.cteTable = cteTable;
@ -39,7 +39,7 @@ public class CteStatement implements Statement {
return cteDefinition; return cteDefinition;
} }
public Statement getCteConsumer() { public CteConsumer getCteConsumer() {
return cteConsumer; return cteConsumer;
} }
} }

View File

@ -13,9 +13,9 @@ import java.util.List;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.mapping.Bindable;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.mutation.internal.cte.CteBasedMutationStrategy; import org.hibernate.query.sqm.mutation.internal.cte.CteBasedMutationStrategy;
import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.Clause;
@ -29,28 +29,26 @@ import org.hibernate.sql.exec.spi.JdbcParameter;
import org.hibernate.sql.exec.spi.JdbcParameterBinding; import org.hibernate.sql.exec.spi.JdbcParameterBinding;
import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.type.spi.TypeConfiguration;
/** /**
* Describes the CTE and exposes ways to consume it * Describes the table definition for the CTE - its name amd its columns
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class CteTable { public class CteTable {
private final EntityMappingType entityDescriptor;
private final SessionFactoryImplementor sessionFactory; private final SessionFactoryImplementor sessionFactory;
private final List<CteColumn> cteColumns; private final List<CteColumn> cteColumns;
public CteTable(EntityMappingType entityDescriptor, RuntimeModelCreationContext runtimeModelCreationContext) { public CteTable(EntityMappingType entityDescriptor, TypeConfiguration typeConfiguration) {
this.entityDescriptor = entityDescriptor;
this.sessionFactory = entityDescriptor.getEntityPersister().getFactory(); this.sessionFactory = entityDescriptor.getEntityPersister().getFactory();
final int numberOfColumns = entityDescriptor.getIdentifierMapping().getJdbcTypeCount( runtimeModelCreationContext.getTypeConfiguration() ); final int numberOfColumns = entityDescriptor.getIdentifierMapping().getJdbcTypeCount( typeConfiguration );
cteColumns = new ArrayList<>( numberOfColumns ); cteColumns = new ArrayList<>( numberOfColumns );
entityDescriptor.getIdentifierMapping().visitColumns( entityDescriptor.getIdentifierMapping().visitColumns(
(columnExpression, containingTableExpression, jdbcMapping) -> cteColumns.add( (columnExpression, containingTableExpression, jdbcMapping) -> cteColumns.add(
new CteColumn( new CteColumn(
this,
"cte_" + columnExpression, "cte_" + columnExpression,
jdbcMapping jdbcMapping
) )
@ -58,6 +56,11 @@ public class CteTable {
); );
} }
public CteTable(List<CteColumn> cteColumns, SessionFactoryImplementor sessionFactory) {
this.cteColumns = cteColumns;
this.sessionFactory = sessionFactory;
}
public String getTableExpression() { public String getTableExpression() {
return CteBasedMutationStrategy.TABLE_NAME; return CteBasedMutationStrategy.TABLE_NAME;
} }
@ -68,12 +71,14 @@ public class CteTable {
public QuerySpec createCteDefinition( public QuerySpec createCteDefinition(
List<?> matchingIds, List<?> matchingIds,
Bindable bindable,
JdbcParameterBindings jdbcParameterBindings, JdbcParameterBindings jdbcParameterBindings,
ExecutionContext executionContext) { ExecutionContext executionContext) {
final QuerySpec querySpec = new QuerySpec( false ); final QuerySpec querySpec = new QuerySpec( false );
final TableReference tableValueConstructorReference = createCteDefinitionTableValueCtor( final TableReference tableValueConstructorReference = createCteDefinitionTableValueCtor(
matchingIds, matchingIds,
bindable,
jdbcParameterBindings, jdbcParameterBindings,
executionContext executionContext
); );
@ -96,7 +101,8 @@ public class CteTable {
} }
private TableReference createCteDefinitionTableValueCtor( private TableReference createCteDefinitionTableValueCtor(
List<?> matchingIds, List<?> matchingValues,
Bindable bindable,
JdbcParameterBindings jdbcParameterBindings, JdbcParameterBindings jdbcParameterBindings,
ExecutionContext executionContext) { ExecutionContext executionContext) {
// use `DerivedTable` as the TableValueConstructor // use `DerivedTable` as the TableValueConstructor
@ -106,17 +112,14 @@ public class CteTable {
final StringBuilder tableValueCtorExpressionBuffer = new StringBuilder( "values(" ); final StringBuilder tableValueCtorExpressionBuffer = new StringBuilder( "values(" );
String rowSeparator = ""; String rowSeparator = "";
int idProcessedCount = 0; for ( Object matchingId : matchingValues ) {
for ( Object matchingId : matchingIds ) {
tableValueCtorExpressionBuffer.append( rowSeparator ); tableValueCtorExpressionBuffer.append( rowSeparator );
tableValueCtorExpressionBuffer.append( '(' ); tableValueCtorExpressionBuffer.append( '(' );
StringHelper.repeat( "?", numberOfColumns, ",", tableValueCtorExpressionBuffer ); StringHelper.repeat( "?", numberOfColumns, ",", tableValueCtorExpressionBuffer );
tableValueCtorExpressionBuffer.append( ')' ); tableValueCtorExpressionBuffer.append( ')' );
final int currentIdPosition = idProcessedCount; bindable.visitJdbcValues(
entityDescriptor.getIdentifierMapping().visitJdbcValues(
matchingId, matchingId,
Clause.IRRELEVANT, Clause.IRRELEVANT,
(value, type) -> { (value, type) -> {
@ -141,7 +144,6 @@ public class CteTable {
); );
rowSeparator = ", "; rowSeparator = ", ";
idProcessedCount++;
} }
tableValueCtorExpressionBuffer.append( ')' ); tableValueCtorExpressionBuffer.append( ')' );

View File

@ -32,7 +32,7 @@ public class CteTableGroup implements TableGroup {
private final TableReference cteTableReference; private final TableReference cteTableReference;
public CteTableGroup(TableReference cteTableReference) { public CteTableGroup(TableReference cteTableReference) {
this.navigablePath = new NavigablePath( CteBasedMutationStrategy.SHORT_NAME ); this.navigablePath = new NavigablePath( CteBasedMutationStrategy.TABLE_NAME );
this.cteTableReference = cteTableReference; this.cteTableReference = cteTableReference;
} }

View File

@ -0,0 +1,44 @@
/*
* 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
*/
/**
* @asciidoc
*
* Support for SQL CTE statements (WITH). The general syntax for a CTE statement is:
*
* ````
* cte:: WITH {cte-label} OPEN_PAREN cteColumns CLOSE_PAREN AS cteDefinition consumer
*
* cteColumns:: cteColumn (, cteColumn)
*
* todo (6.0) : should this include not-null, etc?
* cteColumn:: ...
*
* cteDefinition:: querySpec
*
* todo (6.0) : imo it would be better to have a specific contract `CteConsumer` for things that can occur here, which are:
* * select - `QuerySpec`
* * delete - `DeleteStatement`
* * update - `UpdateStatement`
* * insert-select - `InsertSelectStatement
*
* consumer:: querySpec | deleteStatement | updateStatement | insertSelectStatement
*
* for example, a delete consumer might look like:
*
* with cte_name ( col1, col2, col3 ) as (
* select some_val1, some_val, some_v3
* from some_place
* )
* delete from some_table
* where (some_table_col1, some_table_col2, some_table_col3) in (
* select col1, col2, col3
* from cte_name
* )
* ````
*/
package org.hibernate.sql.ast.tree.cte;

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.ast.tree.delete;
import org.hibernate.sql.ast.spi.SqlAstHelper; import org.hibernate.sql.ast.spi.SqlAstHelper;
import org.hibernate.sql.ast.tree.MutationStatement; import org.hibernate.sql.ast.tree.MutationStatement;
import org.hibernate.sql.ast.tree.cte.CteConsumer;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Junction; import org.hibernate.sql.ast.tree.predicate.Junction;
import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.predicate.Predicate;
@ -15,7 +16,7 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class DeleteStatement implements MutationStatement { public class DeleteStatement implements MutationStatement, CteConsumer {
private final TableReference targetTable; private final TableReference targetTable;
private final Predicate restriction; private final Predicate restriction;

View File

@ -11,6 +11,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.sql.ast.tree.MutationStatement; import org.hibernate.sql.ast.tree.MutationStatement;
import org.hibernate.sql.ast.tree.cte.CteConsumer;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.QuerySpec;
@ -20,7 +21,7 @@ import org.jboss.logging.Logger;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class InsertSelectStatement implements MutationStatement { public class InsertSelectStatement implements MutationStatement, CteConsumer {
private static final Logger log = Logger.getLogger( InsertSelectStatement.class ); private static final Logger log = Logger.getLogger( InsertSelectStatement.class );
private TableReference targetTable; private TableReference targetTable;

View File

@ -13,6 +13,7 @@ import java.util.function.Consumer;
import org.hibernate.sql.ast.spi.SqlAstTreeHelper; import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
import org.hibernate.sql.ast.spi.SqlAstWalker; import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.cte.CteConsumer;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.FromClause; import org.hibernate.sql.ast.tree.from.FromClause;
import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.predicate.Predicate;
@ -21,7 +22,7 @@ import org.hibernate.sql.ast.tree.predicate.PredicateContainer;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class QuerySpec implements SqlAstNode, PredicateContainer { public class QuerySpec implements SqlAstNode, PredicateContainer, CteConsumer {
private final boolean isRoot; private final boolean isRoot;
private final FromClause fromClause; private final FromClause fromClause;

View File

@ -7,19 +7,18 @@
package org.hibernate.sql.ast.tree.update; package org.hibernate.sql.ast.tree.update;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.sql.ast.spi.SqlAstTreeHelper; import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
import org.hibernate.sql.ast.tree.MutationStatement; import org.hibernate.sql.ast.tree.MutationStatement;
import org.hibernate.sql.ast.tree.cte.CteConsumer;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.predicate.PredicateContainer;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class UpdateStatement implements MutationStatement { public class UpdateStatement implements MutationStatement, CteConsumer {
private final TableReference targetTable; private final TableReference targetTable;
private final List<Assignment> assignments; private final List<Assignment> assignments;
private final Predicate restriction; private final Predicate restriction;

View File

@ -0,0 +1,13 @@
/*
* 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.sql.exec.spi;
/**
* @author Steve Ebersole
*/
public interface JdbcUpdate extends JdbcMutation {
}

View File

@ -21,8 +21,6 @@ log4j.logger.org.hibernate.orm.graph=debug
log4j.logger.org.hibernate.orm.query.sqm=debug log4j.logger.org.hibernate.orm.query.sqm=debug
log4j.logger.org.hibernate.orm.query.hql=debug log4j.logger.org.hibernate.orm.query.hql=debug
log4j.logger.org.hibernate.query.sqm.mutation.internal.idtable.TableBasedDeleteHandler=trace
log4j.logger.org.hibernate.tool.hbm2ddl=trace log4j.logger.org.hibernate.tool.hbm2ddl=trace
log4j.logger.org.hibernate.testing.cache=debug log4j.logger.org.hibernate.testing.cache=debug