From 95ff568b3d327ffe5deead6faaa32fa0091117b7 Mon Sep 17 00:00:00 2001 From: gavinking Date: Sun, 16 Feb 2020 01:25:30 +0100 Subject: [PATCH] Add support for HQL 'insert ... values ...' --- .../org/hibernate/grammars/hql/HqlLexer.g4 | 1 + .../org/hibernate/grammars/hql/HqlParser.g4 | 10 +- .../hql/internal/SemanticQueryBuilder.java | 76 +++++++++--- .../query/sqm/SemanticQueryWalker.java | 6 + .../query/sqm/internal/QuerySqmImpl.java | 6 +- .../sqm/internal/SimpleInsertQueryPlan.java | 14 +-- .../query/sqm/internal/SqmTreePrinter.java | 26 ++++ .../idtable/ExecuteWithIdTableHelper.java | 4 +- .../sqm/spi/BaseSemanticQueryWalker.java | 22 ++++ .../sqm/sql/BaseSqmToSqlAstConverter.java | 6 + ...slation.java => SqmInsertTranslation.java} | 12 +- ...anslator.java => SqmInsertTranslator.java} | 7 +- .../query/sqm/sql/SqmTranslatorFactory.java | 2 +- .../sqm/sql/StandardSqmTranslatorFactory.java | 6 +- ....java => StandardSqmInsertTranslator.java} | 114 +++++++++++++++--- .../tree/insert/SqmInsertValuesStatement.java | 41 +++++++ .../query/sqm/tree/insert/SqmValues.java | 23 ++++ .../java/org/hibernate/sql/InsertSelect.java | 3 +- .../sql/ast/SqlAstInsertSelectTranslator.java | 4 +- .../org/hibernate/sql/ast/SqlTreePrinter.java | 12 +- .../StandardSqlAstInsertSelectTranslator.java | 39 +++++- .../sql/ast/tree/cte/package-info.java | 2 +- .../tree/insert/InsertSelectStatement.java | 70 ----------- .../sql/ast/tree/insert/InsertStatement.java | 65 ++++++---- .../hibernate/sql/ast/tree/insert/Values.java | 20 +++ 25 files changed, 420 insertions(+), 171 deletions(-) rename hibernate-core/src/main/java/org/hibernate/query/sqm/sql/{SqmInsertSelectTranslation.java => SqmInsertTranslation.java} (74%) rename hibernate-core/src/main/java/org/hibernate/query/sqm/sql/{SqmInsertSelectTranslator.java => SqmInsertTranslator.java} (58%) rename hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/{StandardSqmInsertSelectTranslator.java => StandardSqmInsertTranslator.java} (53%) create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmValues.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/InsertSelectStatement.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/Values.java diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 index 05cb7ddd99..f363658b5e 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 @@ -269,6 +269,7 @@ TYPE : [tT] [yY] [pP] [eE]; UPDATE : [uU] [pP] [dD] [aA] [tT] [eE]; UPPER : [uU] [pP] [pP] [eE] [rR]; VALUE : [vV] [aA] [lL] [uU] [eE]; +VALUES : [vV] [aA] [lL] [uU] [eE] [sS]; WEEK : [wW] [eE] [eE] [kK]; WHEN : [wW] [hH] [eE] [nN]; WHERE : [wW] [hH] [eE] [rR] [eE]; diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 index 1f8067722f..2621f524ff 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 @@ -56,13 +56,21 @@ assignment ; insertStatement - : INSERT INTO? rootEntity targetFieldsSpec querySpec + : INSERT INTO? rootEntity targetFieldsSpec (querySpec | valuesList) ; targetFieldsSpec : LEFT_PAREN dotIdentifierSequence (COMMA dotIdentifierSequence)* RIGHT_PAREN ; +valuesList + : VALUES values (COMMA values)* + ; + +values + : LEFT_PAREN expression (COMMA expression)* RIGHT_PAREN + ; + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // QUERY SPEC - general structure of root sqm or sub sqm diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index 086f39d27e..f96451f401 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -128,6 +128,9 @@ import org.hibernate.query.sqm.tree.from.SqmJoin; import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin; import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; +import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; @@ -303,7 +306,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre } @Override - public SqmInsertSelectStatement visitInsertStatement(HqlParser.InsertStatementContext ctx) { + public SqmInsertStatement visitInsertStatement(HqlParser.InsertStatementContext ctx) { final SqmRoot root = new SqmRoot<>( visitEntityName( ctx.rootEntity().entityName() ), @@ -311,30 +314,65 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre creationContext.getNodeBuilder() ); - // for now we only support the INSERT-SELECT form - final SqmInsertSelectStatement insertStatement = new SqmInsertSelectStatement<>( root, creationContext.getNodeBuilder() ); - parameterCollector = insertStatement; - final SqmDmlCreationProcessingState processingState = new SqmDmlCreationProcessingState( - insertStatement, - this - ); + if ( ctx.querySpec()!=null ) { + final SqmInsertSelectStatement insertStatement = new SqmInsertSelectStatement<>( root, creationContext.getNodeBuilder() ); + parameterCollector = insertStatement; + final SqmDmlCreationProcessingState processingState = new SqmDmlCreationProcessingState( + insertStatement, + this + ); - processingStateStack.push( processingState ); - processingState.getPathRegistry().register( root ); + processingStateStack.push( processingState ); + processingState.getPathRegistry().register( root ); - try { - insertStatement.setSelectQuerySpec( visitQuerySpec( ctx.querySpec() ) ); + try { + insertStatement.setSelectQuerySpec( visitQuerySpec( ctx.querySpec() ) ); - for ( HqlParser.DotIdentifierSequenceContext stateFieldCtx : ctx.targetFieldsSpec().dotIdentifierSequence() ) { - final SqmPath stateField = (SqmPath) visitDotIdentifierSequence( stateFieldCtx ); - // todo : validate each resolved stateField... - insertStatement.addInsertTargetStateField( stateField ); + for ( HqlParser.DotIdentifierSequenceContext stateFieldCtx : ctx.targetFieldsSpec().dotIdentifierSequence() ) { + final SqmPath stateField = (SqmPath) visitDotIdentifierSequence( stateFieldCtx ); + // todo : validate each resolved stateField... + insertStatement.addInsertTargetStateField( stateField ); + } + + return insertStatement; + } + finally { + processingStateStack.pop(); } - return insertStatement; } - finally { - processingStateStack.pop(); + else { + final SqmInsertValuesStatement insertStatement = new SqmInsertValuesStatement<>( root, creationContext.getNodeBuilder() ); + parameterCollector = insertStatement; + final SqmDmlCreationProcessingState processingState = new SqmDmlCreationProcessingState( + insertStatement, + this + ); + + processingStateStack.push( processingState ); + processingState.getPathRegistry().register( root ); + + try { + for ( HqlParser.ValuesContext values : ctx.valuesList().values() ) { + SqmValues sqmValues = new SqmValues(); + for ( HqlParser.ExpressionContext expressionContext : values.expression() ) { + sqmValues.getExpressions().add( (SqmExpression) expressionContext.accept( this ) ); + } + insertStatement.getValuesList().add( sqmValues ); + } + + for ( HqlParser.DotIdentifierSequenceContext stateFieldCtx : ctx.targetFieldsSpec().dotIdentifierSequence() ) { + final SqmPath stateField = (SqmPath) visitDotIdentifierSequence( stateFieldCtx ); + // todo : validate each resolved stateField... + insertStatement.addInsertTargetStateField( stateField ); + } + + return insertStatement; + } + finally { + processingStateStack.pop(); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java index 1568ac573f..9e4374628e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java @@ -58,6 +58,8 @@ import org.hibernate.query.sqm.tree.from.SqmEntityJoin; import org.hibernate.query.sqm.tree.from.SqmFromClause; import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; +import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; @@ -102,6 +104,8 @@ public interface SemanticQueryWalker { T visitInsertSelectStatement(SqmInsertSelectStatement statement); + T visitInsertValuesStatement(SqmInsertValuesStatement statement); + T visitDeleteStatement(SqmDeleteStatement statement); T visitSelectStatement(SqmSelectStatement statement); @@ -156,6 +160,8 @@ public interface SemanticQueryWalker { T visitSelection(SqmSelection selection); + T visitValues(SqmValues values); + T visitGroupByClause(SqmGroupByClause clause); T visitGrouping(SqmGroupByClause.SqmGrouping grouping); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java index d9d063e4d2..b2057884bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java @@ -573,12 +573,12 @@ public class QuerySqmImpl private NonSelectQueryPlan buildInsertQueryPlan() { final SqmInsertStatement sqmInsert = (SqmInsertStatement) getSqmStatement(); - final String entityNameToUpdate = sqmInsert.getTarget().getReferencedPathSource().getHibernateEntityName(); - final EntityPersister entityDescriptor = getSessionFactory().getDomainModel().findEntityDescriptor( entityNameToUpdate ); +// final String entityNameToUpdate = sqmInsert.getTarget().getReferencedPathSource().getHibernateEntityName(); +// final EntityPersister entityDescriptor = getSessionFactory().getDomainModel().findEntityDescriptor( entityNameToUpdate ); // final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy(); // if ( multiTableStrategy == null ) { - return new SimpleInsertQueryPlan( (SqmInsertSelectStatement) sqmInsert, domainParameterXref ); + return new SimpleInsertQueryPlan( sqmInsert, domainParameterXref ); // } // else { //TODO: diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleInsertQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleInsertQueryPlan.java index a98a7bd672..f38288efd9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleInsertQueryPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleInsertQueryPlan.java @@ -12,11 +12,11 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryParameterImplementor; -import org.hibernate.query.sqm.sql.SqmInsertSelectTranslation; -import org.hibernate.query.sqm.sql.SqmInsertSelectTranslator; +import org.hibernate.query.sqm.sql.SqmInsertTranslation; +import org.hibernate.query.sqm.sql.SqmInsertTranslator; import org.hibernate.query.sqm.sql.SqmTranslatorFactory; import org.hibernate.query.sqm.tree.expression.SqmParameter; -import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; import org.hibernate.sql.ast.SqlAstInsertSelectTranslator; import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.FromClauseAccess; @@ -32,7 +32,7 @@ import java.util.Map; * @author Gavin King */ public class SimpleInsertQueryPlan implements NonSelectQueryPlan { - private final SqmInsertSelectStatement sqmInsert; + private final SqmInsertStatement sqmInsert; private final DomainParameterXref domainParameterXref; private JdbcInsert jdbcInsert; @@ -40,7 +40,7 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan { private Map, Map>> jdbcParamsXref; public SimpleInsertQueryPlan( - SqmInsertSelectStatement sqmInsert, + SqmInsertStatement sqmInsert, DomainParameterXref domainParameterXref) { this.sqmInsert = sqmInsert; this.domainParameterXref = domainParameterXref; @@ -55,7 +55,7 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan { final QueryEngine queryEngine = factory.getQueryEngine(); final SqmTranslatorFactory translatorFactory = queryEngine.getSqmTranslatorFactory(); - final SqmInsertSelectTranslator translator = translatorFactory.createInsertSelectTranslator( + final SqmInsertTranslator translator = translatorFactory.createInsertTranslator( executionContext.getQueryOptions(), domainParameterXref, executionContext.getQueryParameterBindings(), @@ -63,7 +63,7 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan { factory ); - final SqmInsertSelectTranslation sqmInterpretation = translator.translate(sqmInsert); + final SqmInsertTranslation sqmInterpretation = translator.translate(sqmInsert); tableGroupAccess = translator.getFromClauseAccess(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java index be95d2a519..668a573e1b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java @@ -64,6 +64,8 @@ import org.hibernate.query.sqm.tree.from.SqmFrom; import org.hibernate.query.sqm.tree.from.SqmFromClause; import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; +import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; @@ -93,6 +95,7 @@ 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.tree.insert.Values; import org.jboss.logging.Logger; /** @@ -297,6 +300,24 @@ public class SqmTreePrinter implements SemanticQueryWalker { return null; } + @Override + public Object visitInsertValuesStatement(SqmInsertValuesStatement statement) { + if ( DEBUG_ENABLED ) { + processStanza( + "insert", + () -> { + logWithIndentation( "[target = %s]", statement.getTarget().getNavigablePath().getFullPath() ); + processStanza( + "into", + () -> statement.getInsertionTargetPaths().forEach( sqmPath -> sqmPath.accept( this ) ) + ); + } + ); + } + + return null; + } + @Override public Object visitSelectStatement(SqmSelectStatement statement) { if ( DEBUG_ENABLED ) { @@ -578,6 +599,11 @@ public class SqmTreePrinter implements SemanticQueryWalker { return null; } + @Override + public Object visitValues(SqmValues values) { + return null; + } + @Override public Object visitPositionalParameterExpression(SqmPositionalParameter expression) { logWithIndentation( "?%s", expression.getPosition() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithIdTableHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithIdTableHelper.java index cb672778c7..a74d12a8bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithIdTableHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithIdTableHelper.java @@ -31,7 +31,7 @@ import org.hibernate.sql.ast.tree.expression.QueryLiteral; import org.hibernate.sql.ast.tree.from.StandardTableGroup; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; -import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; +import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.select.QuerySpec; @@ -69,7 +69,7 @@ public final class ExecuteWithIdTableHelper { assert mutatingTableGroup.getModelPart() instanceof EntityMappingType; final EntityMappingType mutatingEntityDescriptor = (EntityMappingType) mutatingTableGroup.getModelPart(); - final InsertSelectStatement idTableInsert = new InsertSelectStatement(); + final InsertStatement idTableInsert = new InsertStatement(); final TableReference idTableReference = new TableReference( idTable.getTableExpression(), null, false, factory ); idTableInsert.setTargetTable( idTableReference ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java index f023184d87..10095d6679 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java @@ -60,6 +60,8 @@ import org.hibernate.query.sqm.tree.from.SqmEntityJoin; import org.hibernate.query.sqm.tree.from.SqmFromClause; import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; +import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; @@ -145,6 +147,18 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker statement) { + visitRootPath( statement.getTarget() ); + for ( SqmPath stateField : statement.getInsertionTargetPaths() ) { + stateField.accept( this ); + } + for ( SqmValues sqmValues : statement.getValuesList() ) { + visitValues( sqmValues ); + } + return statement; + } + @Override public Object visitDeleteStatement(SqmDeleteStatement statement) { visitRootPath( statement.getTarget() ); @@ -290,6 +304,14 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker> jdbcParamMap; - public SqmInsertSelectTranslation( - InsertSelectStatement sqlAst, + public SqmInsertTranslation( + InsertStatement sqlAst, Map> jdbcParamMap) { this.sqlAst = sqlAst; this.jdbcParamMap = jdbcParamMap; } - public InsertSelectStatement getSqlAst() { + public InsertStatement getSqlAst() { return sqlAst; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmInsertSelectTranslator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmInsertTranslator.java similarity index 58% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmInsertSelectTranslator.java rename to hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmInsertTranslator.java index c4998d02c2..d0603b1ab7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmInsertSelectTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmInsertTranslator.java @@ -7,11 +7,12 @@ package org.hibernate.query.sqm.sql; import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess; -import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; /** * @author Steve Ebersole */ -public interface SqmInsertSelectTranslator extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, SqmTranslator { - SqmInsertSelectTranslation translate(SqmInsertSelectStatement statement); +public interface SqmInsertTranslator extends SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, SqmTranslator { + SqmInsertTranslation translate(SqmInsertStatement statement); + } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmTranslatorFactory.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmTranslatorFactory.java index a010221bcc..49557a02ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmTranslatorFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmTranslatorFactory.java @@ -32,7 +32,7 @@ public interface SqmTranslatorFactory { LoadQueryInfluencers influencers, SqlAstCreationContext creationContext); - SqmInsertSelectTranslator createInsertSelectTranslator( + SqmInsertTranslator createInsertTranslator( QueryOptions queryOptions, DomainParameterXref domainParameterXref, QueryParameterBindings domainParameterBindings, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/StandardSqmTranslatorFactory.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/StandardSqmTranslatorFactory.java index c62db9e83b..f3c61fd80d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/StandardSqmTranslatorFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/StandardSqmTranslatorFactory.java @@ -12,7 +12,7 @@ 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.internal.StandardSqmDeleteTranslator; -import org.hibernate.query.sqm.sql.internal.StandardSqmInsertSelectTranslator; +import org.hibernate.query.sqm.sql.internal.StandardSqmInsertTranslator; import org.hibernate.query.sqm.sql.internal.StandardSqmSelectTranslator; import org.hibernate.query.sqm.sql.internal.StandardSqmUpdateTranslator; import org.hibernate.sql.ast.spi.SqlAstCreationContext; @@ -55,13 +55,13 @@ public class StandardSqmTranslatorFactory implements SqmTranslatorFactory { } @Override - public SqmInsertSelectTranslator createInsertSelectTranslator( + public SqmInsertTranslator createInsertTranslator( QueryOptions queryOptions, DomainParameterXref domainParameterXref, QueryParameterBindings domainParameterBindings, LoadQueryInfluencers influencers, SqlAstCreationContext creationContext) { - return new StandardSqmInsertSelectTranslator( + return new StandardSqmInsertTranslator( creationContext, queryOptions, domainParameterXref, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertSelectTranslator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertTranslator.java similarity index 53% rename from hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertSelectTranslator.java rename to hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertTranslator.java index c3ebff1ed2..544baf4b17 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertSelectTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertTranslator.java @@ -15,36 +15,45 @@ 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.SqmInsertSelectTranslation; -import org.hibernate.query.sqm.sql.SqmInsertSelectTranslator; +import org.hibernate.query.sqm.sql.SqmInsertTranslation; +import org.hibernate.query.sqm.sql.SqmInsertTranslator; import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.domain.SqmPath; +import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; +import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; +import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.query.sqm.tree.select.SqmSelection; import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.tree.cte.CteStatement; +import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.from.TableGroup; -import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; +import org.hibernate.sql.ast.tree.insert.InsertStatement; +import org.hibernate.sql.ast.tree.insert.Values; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.ast.tree.update.Assignable; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.FetchParent; +import java.util.Collections; import java.util.List; /** * @author Steve Ebersole */ -public class StandardSqmInsertSelectTranslator +public class StandardSqmInsertTranslator extends BaseSqmToSqlAstConverter - implements SqmInsertSelectTranslator, DomainResultCreationState { + implements SqmInsertTranslator, DomainResultCreationState { private final List domainResults = CollectionHelper.arrayList( 10 ); - public StandardSqmInsertSelectTranslator( + public StandardSqmInsertTranslator( SqlAstCreationContext creationContext, QueryOptions queryOptions, DomainParameterXref domainParameterXref, @@ -53,8 +62,15 @@ public class StandardSqmInsertSelectTranslator } @Override - public SqmInsertSelectTranslation translate(SqmInsertSelectStatement sqmStatement) { - return new SqmInsertSelectTranslation( visitInsertSelectStatement( sqmStatement ), getJdbcParamsBySqmParam() ); + public SqmInsertTranslation translate(SqmInsertStatement sqmStatement) { + InsertStatement sqlAst; + if ( sqmStatement instanceof SqmInsertSelectStatement ) { + sqlAst = visitInsertSelectStatement( (SqmInsertSelectStatement) sqmStatement ); + } + else { + sqlAst = visitInsertValuesStatement( (SqmInsertValuesStatement) sqmStatement ); + } + return new SqmInsertTranslation( sqlAst, getJdbcParamsBySqmParam() ); } @Override @@ -63,8 +79,8 @@ public class StandardSqmInsertSelectTranslator } @Override - public InsertSelectStatement visitInsertSelectStatement(SqmInsertSelectStatement sqmStatement) { - final InsertSelectStatement insertSelectStatement = new InsertSelectStatement(); + public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement sqmStatement) { + final InsertStatement insertStatement = new InsertStatement(); final String entityName = sqmStatement.getTarget().getEntityName(); final EntityPersister entityDescriptor = getCreationContext().getDomainModel().getEntityDescriptor( entityName ); @@ -98,19 +114,75 @@ public class StandardSqmInsertSelectTranslator getFromClauseIndex().registerTableGroup( rootPath, rootTableGroup ); - insertSelectStatement.setTargetTable( rootTableGroup.getPrimaryTableReference() ); + insertStatement.setTargetTable( rootTableGroup.getPrimaryTableReference() ); List targetPaths = sqmStatement.getInsertionTargetPaths(); for (SqmPath target : targetPaths) { Assignable assignable = (Assignable) target.accept(this); - insertSelectStatement.addTargetColumnReferences( assignable.getColumnReferences() ); + insertStatement.addTargetColumnReferences( assignable.getColumnReferences() ); } - insertSelectStatement.setSourceSelectStatement( + insertStatement.setSourceSelectStatement( visitQuerySpec( sqmStatement.getSelectQuerySpec() ) ); - return insertSelectStatement; + return insertStatement; + } + finally { + getProcessingStateStack().pop(); + } + } + + @Override + public InsertStatement visitInsertValuesStatement(SqmInsertValuesStatement sqmStatement) { + final InsertStatement insertValuesStatement = new InsertStatement(); + + 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 = sqmStatement.getTarget().getNavigablePath(); + final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup( + rootPath, + sqmStatement.getTarget().getExplicitAlias(), + false, + LockMode.WRITE, + stem -> getSqlAliasBaseGenerator().createSqlAliasBase( stem ), + getSqlExpressionResolver(), + () -> predicate -> additionalRestrictions = predicate, + getCreationContext() + ); + + if ( ! rootTableGroup.getTableReferenceJoins().isEmpty() + || ! rootTableGroup.getTableGroupJoins().isEmpty() ) { + throw new HibernateException( "Not expecting multiple table references for an SQM INSERT-SELECT" ); + } + + getFromClauseIndex().registerTableGroup( rootPath, rootTableGroup ); + + insertValuesStatement.setTargetTable( rootTableGroup.getPrimaryTableReference() ); + + List targetPaths = sqmStatement.getInsertionTargetPaths(); + for (SqmPath target : targetPaths) { + Assignable assignable = (Assignable) target.accept(this); + insertValuesStatement.addTargetColumnReferences( assignable.getColumnReferences() ); + } + + List valuesList = sqmStatement.getValuesList(); + for ( SqmValues sqmValues : valuesList ) { + insertValuesStatement.getValuesList().add( visitValues( sqmValues ) ); + } + + return insertValuesStatement; } finally { getProcessingStateStack().pop(); @@ -141,6 +213,15 @@ public class StandardSqmInsertSelectTranslator return null; } + @Override + public Values visitValues(SqmValues sqmValues) { + Values values = new Values(); + for ( SqmExpression expression : sqmValues.getExpressions() ) { + values.getExpressions().add( (Expression) expression.accept( this ) ); + } + return values; + } + @Override public SelectStatement visitSelectStatement(SqmSelectStatement statement) { final QuerySpec querySpec = visitQuerySpec( statement.getQuerySpec() ); @@ -152,4 +233,9 @@ public class StandardSqmInsertSelectTranslator public SqlAstCreationState getSqlAstCreationState() { return this; } + + @Override + public List visitFetches(FetchParent fetchParent) { + return Collections.emptyList(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java new file mode 100644 index 0000000000..39333d7a4c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java @@ -0,0 +1,41 @@ +/* + * 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.insert; + +import org.hibernate.query.criteria.JpaPredicate; +import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.SemanticQueryWalker; +import org.hibernate.query.sqm.SqmQuerySource; +import org.hibernate.query.sqm.tree.from.SqmRoot; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Gavin King + */ +public class SqmInsertValuesStatement extends AbstractSqmInsertStatement { + private List valuesList = new ArrayList<>(); + + public SqmInsertValuesStatement(SqmRoot targetRoot, NodeBuilder nodeBuilder) { + super( targetRoot, SqmQuerySource.HQL, nodeBuilder ); + } + + public List getValuesList() { + return valuesList; + } + + @Override + public X accept(SemanticQueryWalker walker) { + return walker.visitInsertValuesStatement( this ); + } + + @Override + public JpaPredicate getRestriction() { + return null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmValues.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmValues.java new file mode 100644 index 0000000000..1e4e17139b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmValues.java @@ -0,0 +1,23 @@ +/* + * 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.insert; + +import org.hibernate.query.sqm.tree.expression.SqmExpression; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Gavin King + */ +public class SqmValues { + private List expressions = new ArrayList<>(); + + public List getExpressions() { + return expressions; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java b/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java index ec4bab87df..532d295129 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java @@ -11,13 +11,14 @@ import java.util.List; import org.hibernate.HibernateException; import org.hibernate.dialect.Dialect; +import org.hibernate.sql.ast.tree.insert.InsertStatement; /** * Implementation of InsertSelect. * * @author Steve Ebersole * - * @deprecated (since 6.0) Use {@link org.hibernate.sql.ast.tree.insert.InsertSelectStatement} instead + * @deprecated (since 6.0) Use {@link InsertStatement} instead */ @Deprecated public class InsertSelect { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstInsertSelectTranslator.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstInsertSelectTranslator.java index 59de034c76..c4405cd725 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstInsertSelectTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstInsertSelectTranslator.java @@ -6,12 +6,12 @@ */ package org.hibernate.sql.ast; -import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; +import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.exec.spi.JdbcInsert; /** * @author Steve Ebersole */ public interface SqlAstInsertSelectTranslator extends SqlAstTranslator { - JdbcInsert translate(InsertSelectStatement sqlAst); + JdbcInsert translate(InsertStatement sqlAst); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlTreePrinter.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlTreePrinter.java index d08ca1412e..228ef18fa6 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlTreePrinter.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlTreePrinter.java @@ -42,7 +42,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReferenceJoin; -import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; +import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.predicate.BetweenPredicate; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.ExistsPredicate; @@ -142,19 +142,19 @@ public class SqlTreePrinter implements SqlAstWalker { } ); } - else if ( sqlAstStatement instanceof InsertSelectStatement ) { - final InsertSelectStatement insertSelectStatement = (InsertSelectStatement) sqlAstStatement; + else if ( sqlAstStatement instanceof InsertStatement) { + final InsertStatement insertStatement = (InsertStatement) sqlAstStatement; logNode( "insert-select-statement", () -> { logNode( "target", - () -> logNode( insertSelectStatement.getTargetTable().toString() ) + () -> logNode( insertStatement.getTargetTable().toString() ) ); logNode( "into", () -> { - for ( ColumnReference spec : insertSelectStatement.getTargetColumnReferences() ) { + for ( ColumnReference spec : insertStatement.getTargetColumnReferences() ) { logNode( "target-column", () -> spec.accept( this ) @@ -164,7 +164,7 @@ public class SqlTreePrinter implements SqlAstWalker { ); logNode( "select", - () -> visitQuerySpec( insertSelectStatement.getSourceSelectStatement() ) + () -> visitQuerySpec( insertStatement.getSourceSelectStatement() ) ); } ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/StandardSqlAstInsertSelectTranslator.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/StandardSqlAstInsertSelectTranslator.java index e18fc4c8f3..d2e94ed173 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/StandardSqlAstInsertSelectTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/StandardSqlAstInsertSelectTranslator.java @@ -13,9 +13,10 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; 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.delete.DeleteStatement; import org.hibernate.sql.ast.tree.expression.ColumnReference; -import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.sql.ast.tree.insert.InsertStatement; +import org.hibernate.sql.ast.tree.insert.Values; import org.hibernate.sql.exec.spi.JdbcInsert; import org.hibernate.sql.exec.spi.JdbcParameterBinder; @@ -30,7 +31,7 @@ public class StandardSqlAstInsertSelectTranslator } @Override - public JdbcInsert translate(InsertSelectStatement sqlAst) { + public JdbcInsert translate(InsertStatement sqlAst) { appendSql( "insert into " ); appendSql( sqlAst.getTargetTable().getTableExpression() ); @@ -57,7 +58,33 @@ public class StandardSqlAstInsertSelectTranslator appendSql( ") " ); - visitQuerySpec( sqlAst.getSourceSelectStatement() ); + if ( sqlAst.getSourceSelectStatement()!=null ) { + visitQuerySpec( sqlAst.getSourceSelectStatement() ); + } + else { + appendSql("values"); + boolean firstTuple = true; + for ( Values values : sqlAst.getValuesList() ) { + if (firstTuple) { + firstTuple = false; + } + else { + appendSql(", "); + } + appendSql(" ("); + boolean firstExpr = true; + for ( Expression expression : values.getExpressions() ) { + if (firstExpr) { + firstExpr = false; + } + else { + appendSql(", "); + } + expression.accept( this ); + } + appendSql(")"); + } + } return new JdbcInsert() { @Override @@ -82,7 +109,7 @@ public class StandardSqlAstInsertSelectTranslator @Override public JdbcInsert translate(CteStatement sqlAst) { - assert sqlAst.getCteConsumer() instanceof DeleteStatement; + assert sqlAst.getCteConsumer() instanceof InsertStatement; appendSql( "with " ); appendSql( sqlAst.getCteLabel() ); @@ -104,7 +131,7 @@ public class StandardSqlAstInsertSelectTranslator appendSql( ") " ); - translate( (InsertSelectStatement) sqlAst.getCteConsumer() ); + translate( (InsertStatement) sqlAst.getCteConsumer() ); return new JdbcInsert() { @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/package-info.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/package-info.java index 2d3c6980d7..70adf2f2ec 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/package-info.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/package-info.java @@ -24,7 +24,7 @@ * * select - `QuerySpec` * * delete - `DeleteStatement` * * update - `UpdateStatement` - * * insert-select - `InsertSelectStatement + * * insert-select - `InsertStatement * * consumer:: querySpec | deleteStatement | updateStatement | insertSelectStatement * diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/InsertSelectStatement.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/InsertSelectStatement.java deleted file mode 100644 index e93370e5f8..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/InsertSelectStatement.java +++ /dev/null @@ -1,70 +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.sql.ast.tree.insert; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -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.from.TableReference; -import org.hibernate.sql.ast.tree.select.QuerySpec; - -import org.jboss.logging.Logger; - -/** - * @author Steve Ebersole - */ -public class InsertSelectStatement implements MutationStatement, CteConsumer { - private static final Logger log = Logger.getLogger( InsertSelectStatement.class ); - - private TableReference targetTable; - private List targetColumnReferences; - private QuerySpec sourceSelectStatement = new QuerySpec( true ); - - public TableReference getTargetTable() { - return targetTable; - } - - public void setTargetTable(TableReference targetTable) { - log.tracef( "Setting INSERT-SELECT target table [%s]", targetTable ); - if ( this.targetTable != null ) { - log.debugf( "INSERT-SELECT target table has been set multiple times" ); - } - this.targetTable = targetTable; - } - - public List getTargetColumnReferences() { - return targetColumnReferences == null ? Collections.emptyList() : targetColumnReferences; - } - - public void addTargetColumnReferences(ColumnReference... references) { - if ( targetColumnReferences == null ) { - targetColumnReferences = new ArrayList<>(); - } - - Collections.addAll( this.targetColumnReferences, references ); - } - - public void addTargetColumnReferences(List references) { - if ( targetColumnReferences == null ) { - targetColumnReferences = new ArrayList<>(); - } - - this.targetColumnReferences.addAll( references ); - } - - public QuerySpec getSourceSelectStatement() { - return sourceSelectStatement; - } - - public void setSourceSelectStatement(QuerySpec sourceSelectStatement) { - this.sourceSelectStatement = sourceSelectStatement; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/InsertStatement.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/InsertStatement.java index 2957011f62..83b0601300 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/InsertStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/InsertStatement.java @@ -7,60 +7,73 @@ package org.hibernate.sql.ast.tree.insert; import java.util.ArrayList; +import java.util.Collections; import java.util.List; 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.Expression; import org.hibernate.sql.ast.tree.from.TableReference; +import org.hibernate.sql.ast.tree.select.QuerySpec; + +import org.jboss.logging.Logger; /** * @author Steve Ebersole */ -public class InsertStatement implements MutationStatement { +public class InsertStatement implements MutationStatement, CteConsumer { + private static final Logger log = Logger.getLogger( InsertStatement.class ); + private TableReference targetTable; private List targetColumnReferences; - private List values; - - public InsertStatement(TableReference targetTable) { - this.targetTable = targetTable; - } + private QuerySpec sourceSelectStatement; + private List valuesList = new ArrayList<>(); public TableReference getTargetTable() { return targetTable; } public void setTargetTable(TableReference targetTable) { + log.tracef( "Setting INSERT target table [%s]", targetTable ); + if ( this.targetTable != null ) { + log.debugf( "INSERT target table has been set multiple times" ); + } this.targetTable = targetTable; } public List getTargetColumnReferences() { - return targetColumnReferences; + return targetColumnReferences == null ? Collections.emptyList() : targetColumnReferences; } - public void setTargetColumnReferences(List targetColumnReferences) { - this.targetColumnReferences = targetColumnReferences; - } - - public void addTargetColumnReference(ColumnReference columnReference) { + public void addTargetColumnReferences(ColumnReference... references) { if ( targetColumnReferences == null ) { targetColumnReferences = new ArrayList<>(); } - targetColumnReferences.add( columnReference ); + + Collections.addAll( this.targetColumnReferences, references ); } - public List getValues() { - return values; - } - - public void setValues(List values) { - this.values = values; - } - - public void addValue(Expression expression) { - if ( values == null ) { - values = new ArrayList<>(); + public void addTargetColumnReferences(List references) { + if ( targetColumnReferences == null ) { + targetColumnReferences = new ArrayList<>(); } - values.add( expression ); + + this.targetColumnReferences.addAll( references ); + } + + public QuerySpec getSourceSelectStatement() { + return sourceSelectStatement; + } + + public void setSourceSelectStatement(QuerySpec sourceSelectStatement) { + this.sourceSelectStatement = sourceSelectStatement; + } + + public List getValuesList() { + return valuesList; + } + + public void setValuesList(List valuesList) { + this.valuesList = valuesList; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/Values.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/Values.java new file mode 100644 index 0000000000..94be1c4188 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/insert/Values.java @@ -0,0 +1,20 @@ +/* + * 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.insert; + +import org.hibernate.sql.ast.tree.expression.Expression; + +import java.util.ArrayList; +import java.util.List; + +public class Values { + private List expressions = new ArrayList<>(); + + public List getExpressions() { + return expressions; + } +}