HHH-15393 - Improve write-paths to use mapping model
HHH-15723 - Fix foreign-key modeling
This commit is contained in:
parent
4cce83a779
commit
a9ac98b364
|
@ -9,6 +9,25 @@ appender.stdout.name=STDOUT
|
|||
appender.stdout.layout.type=PatternLayout
|
||||
appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
|
||||
|
||||
|
||||
appender.subsystem.name=subsystem
|
||||
appender.subsystem.type=Console
|
||||
appender.subsystem.layout.type=PatternLayout
|
||||
appender.subsystem.layout.pattern=[subsystem] %5p %15.25c{5} %C{1}:%L - %m%n
|
||||
|
||||
logger.subsystem-root.name=org.hibernate.orm
|
||||
logger.subsystem-root.level=info
|
||||
logger.subsystem-root.additivity=false
|
||||
logger.subsystem-root.appenderRef.subsystem.ref=subsystem
|
||||
|
||||
logger.jdbc-bind.name=org.hibernate.orm.jdbc.bind
|
||||
logger.jdbc-bind.level=trace
|
||||
|
||||
logger.jdbc-extract.name=org.hibernate.orm.jdbc.extract
|
||||
logger.jdbc-extract.level=trace
|
||||
|
||||
|
||||
|
||||
rootLogger.level=info
|
||||
rootLogger.appenderRef.stdout.ref=STDOUT
|
||||
|
||||
|
|
|
@ -23,10 +23,10 @@ import org.hibernate.dialect.pagination.LimitLimitHandler;
|
|||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
|
|
|
@ -6,18 +6,30 @@
|
|||
*/
|
||||
package org.hibernate.community.dialect;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.community.dialect.identity.CacheIdentityColumnSupport;
|
||||
import org.hibernate.community.dialect.sequence.CacheSequenceSupport;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.SimpleDatabaseVersion;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.community.dialect.identity.CacheIdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.lock.*;
|
||||
import org.hibernate.dialect.lock.LockingStrategy;
|
||||
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
|
||||
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
|
||||
import org.hibernate.dialect.lock.SelectLockingStrategy;
|
||||
import org.hibernate.dialect.lock.UpdateLockingStrategy;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.TopLimitHandler;
|
||||
import org.hibernate.community.dialect.sequence.CacheSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -28,9 +40,9 @@ import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
|
|||
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
|
@ -41,11 +53,6 @@ import org.hibernate.type.StandardBasicTypes;
|
|||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
|
|
|
@ -27,11 +27,10 @@ import org.hibernate.sql.ast.tree.expression.Expression;
|
|||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
@ -333,15 +332,6 @@ public class DB2LegacySqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitInsertStatementOnly(InsertStatement statement) {
|
||||
final boolean closeWrapper = renderReturningClause( statement );
|
||||
super.visitInsertStatementOnly( statement );
|
||||
if ( closeWrapper ) {
|
||||
appendSql( ')' );
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean renderReturningClause(MutationStatement statement) {
|
||||
final List<ColumnReference> returningColumns = statement.getReturningColumns();
|
||||
final int size = returningColumns.size();
|
||||
|
@ -429,11 +419,6 @@ public class DB2LegacySqlAstTranslator<T extends JdbcOperation> extends Abstract
|
|||
return getFromDual();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitReturningColumns(MutationStatement mutationStatement) {
|
||||
// For DB2 we use #renderReturningClause to render a wrapper around the DML statement
|
||||
}
|
||||
|
||||
public DatabaseVersion getDB2Version() {
|
||||
return this.getDialect().getVersion();
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ public class DB2iLegacyDialect extends DB2LegacyDialect {
|
|||
@Override
|
||||
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
|
||||
return new StandardSqlAstTranslatorFactory() {
|
||||
|
||||
@Override
|
||||
protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
|
||||
SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.hibernate.dialect.identity.IdentityColumnSupport;
|
|||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
||||
|
@ -44,16 +46,14 @@ import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
|||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.NullOrdering;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
|
|
@ -6,21 +6,16 @@
|
|||
*/
|
||||
package org.hibernate.community.dialect;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.Stack;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.CastTarget;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.FunctionExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcLiteral;
|
||||
|
|
|
@ -414,8 +414,7 @@ public class H2LegacyDialect extends Dialect {
|
|||
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
|
||||
return new StandardSqlAstTranslatorFactory() {
|
||||
@Override
|
||||
protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
|
||||
SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
return new H2LegacySqlAstTranslator<>( sessionFactory, statement );
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,19 +7,22 @@
|
|||
package org.hibernate.community.dialect;
|
||||
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.community.dialect.identity.InformixIdentityColumnSupport;
|
||||
import org.hibernate.community.dialect.pagination.FirstLimitHandler;
|
||||
import org.hibernate.community.dialect.pagination.SkipFirstLimitHandler;
|
||||
import org.hibernate.community.dialect.sequence.InformixSequenceSupport;
|
||||
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorInformixDatabaseImpl;
|
||||
import org.hibernate.community.dialect.unique.InformixUniqueDelegate;
|
||||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.Replacer;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.community.dialect.identity.InformixIdentityColumnSupport;
|
||||
import org.hibernate.community.dialect.pagination.FirstLimitHandler;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.community.dialect.pagination.SkipFirstLimitHandler;
|
||||
import org.hibernate.community.dialect.sequence.InformixSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.community.dialect.unique.InformixUniqueDelegate;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
|
@ -29,17 +32,15 @@ import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
|||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslator;
|
||||
|
@ -55,7 +56,6 @@ import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
|||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorInformixDatabaseImpl;
|
||||
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
||||
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
|
|
|
@ -66,8 +66,7 @@ public class InformixSqmToSqlAstConverter<T extends Statement> extends BaseSqmTo
|
|||
new NamedTableReference(
|
||||
"(select 1)",
|
||||
"dummy_(x)",
|
||||
false,
|
||||
getCreationContext().getSessionFactory()
|
||||
false
|
||||
),
|
||||
null,
|
||||
getCreationContext().getSessionFactory()
|
||||
|
|
|
@ -22,22 +22,22 @@ import org.hibernate.dialect.identity.IdentityColumnSupport;
|
|||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.sequence.ANSISequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslator;
|
||||
|
|
|
@ -66,8 +66,7 @@ public class IngresSqmToSqlAstConverter<T extends Statement> extends BaseSqmToSq
|
|||
new NamedTableReference(
|
||||
"(select 1)",
|
||||
"dummy_(x)",
|
||||
false,
|
||||
getCreationContext().getSessionFactory()
|
||||
false
|
||||
),
|
||||
null,
|
||||
getCreationContext().getSessionFactory()
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.sql.DatabaseMetaData;
|
|||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.InnoDBStorageEngine;
|
||||
import org.hibernate.dialect.MySQLStorageEngine;
|
||||
import org.hibernate.dialect.NationalizationSupport;
|
||||
|
|
|
@ -23,8 +23,8 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.sqm.TrimSpec;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.TrimSpec;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
|
|
|
@ -19,10 +19,10 @@ import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
|
|||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.pagination.LimitLimitHandler;
|
||||
import org.hibernate.dialect.sequence.NoSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
|
@ -47,17 +49,15 @@ import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
|||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.NullOrdering;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
@ -83,7 +83,33 @@ import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
|||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.BIGINT;
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.BIT;
|
||||
import static org.hibernate.type.SqlTypes.BLOB;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.CHAR;
|
||||
import static org.hibernate.type.SqlTypes.CLOB;
|
||||
import static org.hibernate.type.SqlTypes.DECIMAL;
|
||||
import static org.hibernate.type.SqlTypes.DOUBLE;
|
||||
import static org.hibernate.type.SqlTypes.FLOAT;
|
||||
import static org.hibernate.type.SqlTypes.GEOMETRY;
|
||||
import static org.hibernate.type.SqlTypes.INTEGER;
|
||||
import static org.hibernate.type.SqlTypes.JSON;
|
||||
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCLOB;
|
||||
import static org.hibernate.type.SqlTypes.NUMERIC;
|
||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.REAL;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
|
||||
/**
|
||||
* A {@linkplain Dialect SQL dialect} for MySQL 5 and above.
|
||||
|
|
|
@ -31,10 +31,10 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.TrimSpec;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
|
|
|
@ -8,13 +8,12 @@ package org.hibernate.community.dialect;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
|
|
|
@ -36,12 +36,12 @@ import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
|
|||
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.NullOrdering;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.TrimSpec;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
|
|
|
@ -29,7 +29,14 @@ import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
|||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.DATE;
|
||||
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCLOB;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
|
||||
/**
|
||||
* SQL Dialect for Sybase/SQL Anywhere
|
||||
|
|
|
@ -63,12 +63,7 @@ public class SybaseLegacySqmToSqlAstConverter<T extends Statement> extends BaseS
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
new NamedTableReference(
|
||||
"(select 1)",
|
||||
"dummy_(x)",
|
||||
false,
|
||||
getCreationContext().getSessionFactory()
|
||||
),
|
||||
new NamedTableReference( "(select 1)", "dummy_(x)", false ),
|
||||
null,
|
||||
getCreationContext().getSessionFactory()
|
||||
)
|
||||
|
|
|
@ -6,19 +6,27 @@
|
|||
*/
|
||||
package org.hibernate.community.dialect;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.model.relational.QualifiedNameImpl;
|
||||
import org.hibernate.boot.model.relational.QualifiedTableName;
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.community.dialect.identity.Teradata14IdentityColumnSupport;
|
||||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.community.dialect.identity.Teradata14IdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.TopLimitHandler;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
|
||||
|
@ -27,14 +35,12 @@ import org.hibernate.mapping.Column;
|
|||
import org.hibernate.mapping.Index;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ForUpdateFragment;
|
||||
|
@ -52,12 +58,6 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
|
|
|
@ -6,28 +6,38 @@
|
|||
*/
|
||||
package org.hibernate.community.dialect;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.community.dialect.pagination.TimesTenLimitHandler;
|
||||
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorTimesTenDatabaseImpl;
|
||||
import org.hibernate.community.dialect.sequence.TimesTenSequenceSupport;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.RowLockStrategy;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.lock.*;
|
||||
import org.hibernate.dialect.lock.LockingStrategy;
|
||||
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
|
||||
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
|
||||
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
|
||||
import org.hibernate.dialect.lock.SelectLockingStrategy;
|
||||
import org.hibernate.dialect.lock.UpdateLockingStrategy;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.community.dialect.pagination.TimesTenLimitHandler;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.community.dialect.sequence.TimesTenSequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -35,7 +45,6 @@ import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
|||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorTimesTenDatabaseImpl;
|
||||
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
@ -43,7 +52,6 @@ import org.hibernate.type.descriptor.jdbc.JdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.sql.Types;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
|
||||
|
|
|
@ -9,13 +9,12 @@ package org.hibernate.community.dialect;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||
|
|
|
@ -25,6 +25,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
* @apiNote Intended for use at development-time for developers to better understand
|
||||
* the lifecycle of the annotated element.
|
||||
*
|
||||
* @see Deprecated#forRemoval()
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Target({METHOD, FIELD, TYPE, PACKAGE, CONSTRUCTOR, TYPE_PARAMETER, TYPE_USE})
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.hibernate.cache.spi.access.CollectionDataAccess;
|
|||
import org.hibernate.cache.spi.access.EntityDataAccess;
|
||||
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
||||
|
@ -30,9 +29,8 @@ import org.hibernate.persister.collection.CollectionPersister;
|
|||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.sqm.tree.SqmDmlStatement;
|
||||
import org.hibernate.query.sqm.tree.SqmQuery;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
|
||||
|
||||
/**
|
||||
* An {@link org.hibernate.engine.spi.ActionQueue} {@link Executable} for
|
||||
|
@ -148,7 +146,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
|
|||
public static void schedule(SharedSessionContractImplementor session, SqmDmlStatement<?> statement) {
|
||||
final List<EntityPersister> entityPersisters = new ArrayList<>( 1 );
|
||||
final MappingMetamodelImplementor metamodel = session.getFactory().getRuntimeMetamodels().getMappingMetamodel();
|
||||
if ( !( statement instanceof InsertStatement ) ) {
|
||||
if ( !( statement instanceof InsertSelectStatement ) ) {
|
||||
entityPersisters.add( metamodel.getEntityDescriptor( statement.getTarget().getEntityName() ) );
|
||||
}
|
||||
for ( SqmCteStatement<?> cteStatement : statement.getCteStatements() ) {
|
||||
|
|
|
@ -153,7 +153,10 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
|
|||
}
|
||||
else {
|
||||
//then by fk
|
||||
return persister.getKeyType().compare( key, action.key );
|
||||
return persister.getAttributeMapping().getKeyDescriptor().compare( key, action.key );
|
||||
// //noinspection unchecked
|
||||
// final JavaType<Object> javaType = (JavaType<Object>) persister.getAttributeMapping().getKeyDescriptor().getJavaType();
|
||||
// return javaType.getComparator().compare( key, action.key );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,9 +87,8 @@ public @interface Table {
|
|||
* If enabled, Hibernate will insert a row only if the columns of the secondary table
|
||||
* would not all be null, and will always use an outer join to read the columns. Thus,
|
||||
* by default, Hibernate avoids creating a row of null values.
|
||||
* <p>
|
||||
* <em>Only applies to secondary tables.</em>
|
||||
*
|
||||
* @apiNote Only relevant for secondary tables
|
||||
* @deprecated use {@link SecondaryRow#optional()}
|
||||
*/
|
||||
@Deprecated(since = "6.2")
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
*/
|
||||
package org.hibernate.cache.spi.entry;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Operations for assembly and disassembly of an array of property values.
|
||||
*/
|
||||
|
@ -35,7 +35,7 @@ class CacheEntryHelper {
|
|||
final boolean[] nonCacheable,
|
||||
final SharedSessionContractImplementor session,
|
||||
final Object owner) {
|
||||
Serializable[] disassembled = new Serializable[row.length];
|
||||
Serializable[] disassembled = new Serializable[types.length];
|
||||
for ( int i = 0; i < row.length; i++ ) {
|
||||
if ( nonCacheable!=null && nonCacheable[i] ) {
|
||||
disassembled[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.SessionFactoryObserver;
|
|||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
import org.hibernate.cache.spi.TimestampsCacheFactory;
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
|
||||
import org.hibernate.id.enhanced.ImplicitDatabaseObjectNamingStrategy;
|
||||
import org.hibernate.jpa.LegacySpecHints;
|
||||
import org.hibernate.jpa.SpecHints;
|
||||
|
@ -1011,7 +1012,7 @@ public interface AvailableSettings {
|
|||
String STATEMENT_BATCH_SIZE = "hibernate.jdbc.batch_size";
|
||||
|
||||
/**
|
||||
* Specifies a custom {@link org.hibernate.engine.jdbc.batch.spi.BatchBuilder}.
|
||||
* Specifies a custom {@link BatchBuilder}.
|
||||
*/
|
||||
String BATCH_STRATEGY = "hibernate.jdbc.factory_class";
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.Incubating;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.mutation.InsertRowsCoordinator;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
|
@ -221,6 +222,22 @@ public interface PersistentCollection<E> extends LazyInitializable {
|
|||
*/
|
||||
boolean entryExists(Object entry, int i);
|
||||
|
||||
/**
|
||||
* Whether the given entry should be included in recreation events
|
||||
*
|
||||
* @apiNote Defined to match signature of {@link InsertRowsCoordinator.EntryFilter#include}
|
||||
*/
|
||||
default boolean includeInRecreate(
|
||||
Object entry,
|
||||
int i,
|
||||
PersistentCollection<?> collection,
|
||||
PluralAttributeMapping attributeDescriptor) {
|
||||
assert collection == this;
|
||||
assert attributeDescriptor != null;
|
||||
|
||||
return entryExists( entry, i );
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to insert this element?
|
||||
*
|
||||
|
@ -232,6 +249,39 @@ public interface PersistentCollection<E> extends LazyInitializable {
|
|||
*/
|
||||
boolean needsInserting(Object entry, int i, Type elemType);
|
||||
|
||||
/**
|
||||
* Whether to include the entry for insertion operations
|
||||
*
|
||||
* @apiNote Defined to match signature of {@link InsertRowsCoordinator.EntryFilter#include}
|
||||
*/
|
||||
default boolean includeInInsert(
|
||||
Object entry,
|
||||
int entryPosition,
|
||||
PersistentCollection<?> collection,
|
||||
PluralAttributeMapping attributeDescriptor) {
|
||||
assert collection == this;
|
||||
assert attributeDescriptor != null;
|
||||
|
||||
return needsInserting( entry, entryPosition, attributeDescriptor.getCollectionDescriptor().getElementType() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to update this element?
|
||||
*
|
||||
* @param entry The collection element to check
|
||||
* @param entryPosition The index (for indexed collections)
|
||||
* @param attributeDescriptor The type for the element
|
||||
* @return {@code true} if the element needs updating
|
||||
*/
|
||||
default boolean needsUpdating(
|
||||
Object entry,
|
||||
int entryPosition,
|
||||
PluralAttributeMapping attributeDescriptor) {
|
||||
assert attributeDescriptor != null;
|
||||
|
||||
return needsUpdating( entry, entryPosition, attributeDescriptor.getCollectionDescriptor().getElementType() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to update this element?
|
||||
*
|
||||
|
|
|
@ -6,6 +6,36 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.FilterReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.ScrollMode;
|
||||
|
@ -23,10 +53,17 @@ import org.hibernate.dialect.sequence.HANASequenceSupport;
|
|||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.*;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BlobImplementer;
|
||||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.ClobImplementer;
|
||||
import org.hibernate.engine.jdbc.NClobImplementer;
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.*;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
||||
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
|
@ -39,11 +76,12 @@ import org.hibernate.internal.util.JdbcExceptionHelper;
|
|||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
|
||||
import org.hibernate.procedure.spi.CallableStatementSupport;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.NullOrdering;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
|
@ -62,27 +100,26 @@ import org.hibernate.type.descriptor.WrapperOptions;
|
|||
import org.hibernate.type.descriptor.java.DataHelper;
|
||||
import org.hibernate.type.descriptor.java.DoubleJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.*;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicBinder;
|
||||
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
|
||||
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.DecimalJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NCharJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NClobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NVarcharJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.NumericJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
|
||||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.internal.BasicTypeImpl;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.*;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.CHAR;
|
||||
|
|
|
@ -19,8 +19,6 @@ import java.util.TimeZone;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.PessimisticLockException;
|
||||
|
@ -73,6 +71,8 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.query.sqm.TemporalUnit.DAY;
|
||||
import static org.hibernate.query.sqm.TemporalUnit.NATIVE;
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.dialect.function.CastingConcatFunction;
|
||||
|
@ -33,9 +40,9 @@ import org.hibernate.internal.util.JdbcExceptionHelper;
|
|||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.cte.CteMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
|
@ -55,23 +62,34 @@ import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
|||
import org.hibernate.type.JavaObjectType;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.*;
|
||||
import org.hibernate.type.descriptor.jdbc.CharJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.DecimalJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ObjectNullResolvingJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.XmlJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
|
||||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.BLOB;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.CLOB;
|
||||
import static org.hibernate.type.SqlTypes.DECIMAL;
|
||||
import static org.hibernate.type.SqlTypes.NUMERIC;
|
||||
import static org.hibernate.type.SqlTypes.SQLXML;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TIME_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
|
||||
/**
|
||||
* A {@linkplain Dialect SQL dialect} for DB2.
|
||||
|
|
|
@ -26,11 +26,11 @@ import org.hibernate.sql.ast.tree.expression.Expression;
|
|||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
|
||||
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
|
@ -339,7 +339,7 @@ public class DB2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAst
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void visitInsertStatementOnly(InsertStatement statement) {
|
||||
protected void visitInsertStatementOnly(InsertSelectStatement statement) {
|
||||
final boolean closeWrapper = renderReturningClause( statement );
|
||||
super.visitInsertStatementOnly( statement );
|
||||
if ( closeWrapper ) {
|
||||
|
@ -435,7 +435,7 @@ public class DB2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAst
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void visitReturningColumns(MutationStatement mutationStatement) {
|
||||
protected void visitReturningColumns(List<ColumnReference> returningColumns) {
|
||||
// For DB2 we use #renderReturningClause to render a wrapper around the DML statement
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.identity.DB2zIdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.DB2zIdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.FetchLimitHandler;
|
||||
import org.hibernate.dialect.pagination.LegacyDB2LimitHandler;
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
package org.hibernate.dialect;
|
||||
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.identity.DB2zIdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
|
@ -28,6 +26,8 @@ import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
|||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
|
|
|
@ -6,14 +6,18 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
|
||||
import org.hibernate.dialect.function.CastingConcatFunction;
|
||||
import org.hibernate.dialect.function.ChrLiteralEmulation;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.CountFunction;
|
||||
import org.hibernate.dialect.function.DerbyLpadEmulation;
|
||||
import org.hibernate.dialect.function.DerbyRpadEmulation;
|
||||
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
|
||||
import org.hibernate.dialect.function.InsertSubstringOverlayEmulation;
|
||||
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
|
@ -21,6 +25,8 @@ import org.hibernate.dialect.pagination.DerbyLimitHandler;
|
|||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.sequence.DerbySequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
|
@ -32,16 +38,14 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
|||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
@ -67,13 +71,25 @@ import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.BLOB;
|
||||
import static org.hibernate.type.SqlTypes.CHAR;
|
||||
import static org.hibernate.type.SqlTypes.CLOB;
|
||||
import static org.hibernate.type.SqlTypes.DECIMAL;
|
||||
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCLOB;
|
||||
import static org.hibernate.type.SqlTypes.NUMERIC;
|
||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
|
||||
/**
|
||||
* A {@linkplain Dialect SQL dialect} for Apache Derby.
|
||||
|
|
|
@ -91,6 +91,7 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
|||
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
||||
import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.exception.spi.ConversionContext;
|
||||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||
|
@ -110,6 +111,7 @@ import org.hibernate.mapping.Table;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
|
||||
import org.hibernate.procedure.spi.CallableStatementSupport;
|
||||
import org.hibernate.query.Query;
|
||||
|
@ -137,6 +139,9 @@ import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
|||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.StringBuilderSqlAppender;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.internal.TableUpsert;
|
||||
import org.hibernate.sql.model.jdbc.OptionalTableUpdateOperation;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
|
||||
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
||||
|
@ -3972,6 +3977,13 @@ public abstract class Dialect implements ConversionContext {
|
|||
return true;
|
||||
}
|
||||
|
||||
public MutationOperation createUpsertOperation(
|
||||
EntityMutationTarget mutationTarget,
|
||||
TableUpsert tableUpsert,
|
||||
SessionFactoryImplementor factory) {
|
||||
return new OptionalTableUpdateOperation( mutationTarget, tableUpsert, factory );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is there some way to disable foreign key constraint checking while
|
||||
* truncating tables? (If there's no way to do it, and if we can't
|
||||
|
|
|
@ -88,10 +88,10 @@ import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
|
|||
import static org.hibernate.type.SqlTypes.NCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NUMERIC;
|
||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
|
||||
import static org.hibernate.type.SqlTypes.UUID;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
|
||||
|
@ -758,7 +758,9 @@ public class H2Dialect extends Dialect {
|
|||
|
||||
@Override
|
||||
public IdentityColumnSupport getIdentityColumnSupport() {
|
||||
return getVersion().isSameOrAfter( 2 ) ? H2FinalTableIdentityColumnSupport.INSTANCE : H2IdentityColumnSupport.INSTANCE;
|
||||
return getVersion().isSameOrAfter( 2 )
|
||||
? H2FinalTableIdentityColumnSupport.INSTANCE
|
||||
: H2IdentityColumnSupport.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.dialect;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.dialect.identity.H2IdentityColumnSupport;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
|
@ -18,9 +19,9 @@ import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
|||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteContainer;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteTableGroup;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
|
@ -34,6 +35,7 @@ import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
|
|||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
import org.hibernate.sql.ast.tree.select.SelectClause;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.sql.model.internal.TableInsertStandard;
|
||||
|
||||
/**
|
||||
* A SQL AST translator for H2.
|
||||
|
@ -48,6 +50,39 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
|
|||
super( sessionFactory, statement );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitStandardTableInsert(TableInsertStandard tableInsert) {
|
||||
if ( CollectionHelper.isNotEmpty( tableInsert.getReturningColumns() ) ) {
|
||||
visitReturningInsertStatement( tableInsert );
|
||||
}
|
||||
else {
|
||||
super.visitStandardTableInsert( tableInsert );
|
||||
}
|
||||
}
|
||||
|
||||
public void visitReturningInsertStatement(TableInsertStandard tableInsert) {
|
||||
assert tableInsert.getReturningColumns() != null
|
||||
&& !tableInsert.getReturningColumns().isEmpty();
|
||||
|
||||
final H2IdentityColumnSupport identitySupport = (H2IdentityColumnSupport) getSessionFactory()
|
||||
.getJdbcServices()
|
||||
.getDialect()
|
||||
.getIdentityColumnSupport();
|
||||
|
||||
identitySupport.render(
|
||||
tableInsert,
|
||||
this::appendSql,
|
||||
(columnReference) -> columnReference.accept( this ),
|
||||
() -> super.visitStandardTableInsert( tableInsert ),
|
||||
getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitReturningColumns(List<ColumnReference> returningColumns) {
|
||||
// do nothing - this is handled via `#visitReturningInsertStatement`
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCteContainer(CteContainer cteContainer) {
|
||||
// H2 has various bugs in different versions that make it impossible to use CTEs with parameters reliably
|
||||
|
|
|
@ -41,11 +41,11 @@ import org.hibernate.internal.util.JdbcExceptionHelper;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.NullOrdering;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
|
|
|
@ -24,6 +24,8 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.pagination.LimitLimitHandler;
|
||||
import org.hibernate.dialect.sequence.NoSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.engine.jdbc.Size;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
|
@ -39,18 +41,16 @@ import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
|||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.NullOrdering;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
||||
|
@ -77,7 +77,33 @@ import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
|||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.BIGINT;
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.BIT;
|
||||
import static org.hibernate.type.SqlTypes.BLOB;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.CHAR;
|
||||
import static org.hibernate.type.SqlTypes.CLOB;
|
||||
import static org.hibernate.type.SqlTypes.DECIMAL;
|
||||
import static org.hibernate.type.SqlTypes.DOUBLE;
|
||||
import static org.hibernate.type.SqlTypes.FLOAT;
|
||||
import static org.hibernate.type.SqlTypes.GEOMETRY;
|
||||
import static org.hibernate.type.SqlTypes.INTEGER;
|
||||
import static org.hibernate.type.SqlTypes.JSON;
|
||||
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCLOB;
|
||||
import static org.hibernate.type.SqlTypes.NUMERIC;
|
||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.REAL;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
|
||||
/**
|
||||
* A {@linkplain Dialect SQL dialect} for MySQL 5.7 and above.
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.hibernate.dialect.pagination.LimitHandler;
|
|||
import org.hibernate.dialect.pagination.Oracle12LimitHandler;
|
||||
import org.hibernate.dialect.sequence.OracleSequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.dialect.unique.CreateTableUniqueDelegate;
|
||||
import org.hibernate.dialect.unique.UniqueDelegate;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
|
@ -48,19 +50,18 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
|
||||
import org.hibernate.procedure.spi.CallableStatementSupport;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
|
@ -80,6 +81,9 @@ import org.hibernate.type.descriptor.jdbc.JsonBlobJdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.NullJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
|
@ -90,13 +94,25 @@ import static org.hibernate.query.sqm.TemporalUnit.MINUTE;
|
|||
import static org.hibernate.query.sqm.TemporalUnit.MONTH;
|
||||
import static org.hibernate.query.sqm.TemporalUnit.SECOND;
|
||||
import static org.hibernate.query.sqm.TemporalUnit.YEAR;
|
||||
|
||||
import org.hibernate.query.sqm.produce.function.FunctionParameterType;
|
||||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.ARRAY;
|
||||
import static org.hibernate.type.SqlTypes.BIGINT;
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.DATE;
|
||||
import static org.hibernate.type.SqlTypes.DECIMAL;
|
||||
import static org.hibernate.type.SqlTypes.GEOMETRY;
|
||||
import static org.hibernate.type.SqlTypes.INTEGER;
|
||||
import static org.hibernate.type.SqlTypes.JSON;
|
||||
import static org.hibernate.type.SqlTypes.NUMERIC;
|
||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.REAL;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.SQLXML;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIME_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
|
||||
/**
|
||||
* A {@linkplain Dialect SQL dialect} for Oracle 8i and above.
|
||||
|
|
|
@ -11,10 +11,9 @@ import java.util.List;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.Stack;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.sqm.FrameExclusion;
|
||||
import org.hibernate.query.sqm.FrameKind;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
|
@ -22,8 +21,6 @@ import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
|||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteMaterialization;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.FunctionExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
|
@ -34,7 +31,7 @@ import org.hibernate.sql.ast.tree.from.FunctionTableReference;
|
|||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.ValuesTableReference;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
|
||||
import org.hibernate.sql.ast.tree.insert.Values;
|
||||
import org.hibernate.sql.ast.tree.select.QueryGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
|
@ -175,7 +172,7 @@ public class OracleSqlAstTranslator<T extends JdbcOperation> extends AbstractSql
|
|||
// When the query has no sort specifications and offset, we want to use the ROWNUM pagination as that is a special locking case
|
||||
return !queryPart.hasSortSpecifications() && !hasOffset( queryPart )
|
||||
// Workaround an Oracle bug, segmentation fault for insert queries with a plain query group and fetch clause
|
||||
|| queryPart instanceof QueryGroup && getClauseStack().isEmpty() && getStatement() instanceof InsertStatement;
|
||||
|| queryPart instanceof QueryGroup && getClauseStack().isEmpty() && getStatement() instanceof InsertSelectStatement;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
|
@ -83,6 +82,8 @@ import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
|
|||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.query.sqm.TemporalUnit.DAY;
|
||||
import static org.hibernate.query.sqm.TemporalUnit.EPOCH;
|
||||
|
@ -94,8 +95,8 @@ import static org.hibernate.type.SqlTypes.BINARY;
|
|||
import static org.hibernate.type.SqlTypes.BLOB;
|
||||
import static org.hibernate.type.SqlTypes.CHAR;
|
||||
import static org.hibernate.type.SqlTypes.CLOB;
|
||||
import static org.hibernate.type.SqlTypes.GEOGRAPHY;
|
||||
import static org.hibernate.type.SqlTypes.FLOAT;
|
||||
import static org.hibernate.type.SqlTypes.GEOGRAPHY;
|
||||
import static org.hibernate.type.SqlTypes.GEOMETRY;
|
||||
import static org.hibernate.type.SqlTypes.INET;
|
||||
import static org.hibernate.type.SqlTypes.JSON;
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteMaterialization;
|
||||
|
|
|
@ -6,7 +6,18 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import org.hibernate.*;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.QueryTimeoutException;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.boot.model.relational.QualifiedSequenceName;
|
||||
|
@ -35,12 +46,12 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.exception.LockTimeoutException;
|
||||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.TrimSpec;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
|
@ -64,21 +75,31 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
|||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.query.sqm.TemporalUnit.NANOSECOND;
|
||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.INTEGER;
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.BLOB;
|
||||
import static org.hibernate.type.SqlTypes.CLOB;
|
||||
import static org.hibernate.type.SqlTypes.DATE;
|
||||
import static org.hibernate.type.SqlTypes.DOUBLE;
|
||||
import static org.hibernate.type.SqlTypes.GEOGRAPHY;
|
||||
import static org.hibernate.type.SqlTypes.GEOMETRY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCLOB;
|
||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.OTHER;
|
||||
import static org.hibernate.type.SqlTypes.SQLXML;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.UUID;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
|
||||
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
|
||||
|
|
|
@ -10,16 +10,14 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
|
|
|
@ -34,10 +34,10 @@ import org.hibernate.mapping.ForeignKey;
|
|||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UniqueKey;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
|
@ -52,7 +52,31 @@ import org.hibernate.type.StandardBasicTypes;
|
|||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.BIGINT;
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.BLOB;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.CHAR;
|
||||
import static org.hibernate.type.SqlTypes.CLOB;
|
||||
import static org.hibernate.type.SqlTypes.DECIMAL;
|
||||
import static org.hibernate.type.SqlTypes.DOUBLE;
|
||||
import static org.hibernate.type.SqlTypes.FLOAT;
|
||||
import static org.hibernate.type.SqlTypes.INTEGER;
|
||||
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCLOB;
|
||||
import static org.hibernate.type.SqlTypes.NUMERIC;
|
||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.REAL;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
|
||||
/**
|
||||
* A {@linkplain Dialect SQL dialect} for Cloud Spanner.
|
||||
|
|
|
@ -45,7 +45,11 @@ import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
|||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
|
||||
import static org.hibernate.type.SqlTypes.*;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.DATE;
|
||||
import static org.hibernate.type.SqlTypes.TIME;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
|
||||
/**
|
||||
* A {@linkplain Dialect SQL dialect} for Sybase Adaptive Server Enterprise 16 and above.
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
*/
|
||||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.function.CountFunction;
|
||||
|
@ -19,13 +23,13 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
|||
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.query.sqm.CastType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.TrimSpec;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
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.SqmTranslator;
|
||||
import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
|
||||
|
@ -49,10 +53,6 @@ import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcType;
|
|||
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
|
||||
|
|
|
@ -66,8 +66,7 @@ public class SybaseSqmToSqlAstConverter<T extends Statement> extends BaseSqmToSq
|
|||
new NamedTableReference(
|
||||
"(select 1)",
|
||||
"dummy_(x)",
|
||||
false,
|
||||
getCreationContext().getSessionFactory()
|
||||
false
|
||||
),
|
||||
null,
|
||||
getCreationContext().getSessionFactory()
|
||||
|
|
|
@ -1,74 +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.dialect.identity;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.insert.AbstractReturningDelegate;
|
||||
import org.hibernate.id.insert.IdentifierGeneratingInsert;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
|
||||
/**
|
||||
* Delegate for dealing with IDENTITY columns using JDBC3 getGeneratedKeys
|
||||
*
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class GetGeneratedKeysDelegate
|
||||
extends AbstractReturningDelegate
|
||||
implements InsertGeneratedIdentifierDelegate {
|
||||
private final PostInsertIdentityPersister persister;
|
||||
private final Dialect dialect;
|
||||
|
||||
public GetGeneratedKeysDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
|
||||
super( persister );
|
||||
this.persister = persister;
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) {
|
||||
IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect );
|
||||
insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] );
|
||||
return insert;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreparedStatement prepare(String insertSQL, SharedSessionContractImplementor session) throws SQLException {
|
||||
return session
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( insertSQL, PreparedStatement.RETURN_GENERATED_KEYS );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object executeAndExtract(PreparedStatement insert, SharedSessionContractImplementor session)
|
||||
throws SQLException {
|
||||
session.getJdbcCoordinator().getResultSetReturn().executeUpdate( insert );
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
rs = insert.getGeneratedKeys();
|
||||
return IdentifierGeneratorHelper.getGeneratedIdentity(
|
||||
rs,
|
||||
persister.getRootTableKeyColumnNames()[0],
|
||||
persister.getIdentifierType(),
|
||||
session.getJdbcServices().getJdbcEnvironment().getDialect()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
if ( rs != null ) {
|
||||
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( rs, insert );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,13 @@
|
|||
*/
|
||||
package org.hibernate.dialect.identity;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.model.ast.TableInsert;
|
||||
|
||||
/**
|
||||
* Identity column support for H2 2+ versions
|
||||
* @author Jan Schatteman
|
||||
|
@ -26,4 +33,28 @@ public class H2FinalTableIdentityColumnSupport extends H2IdentityColumnSupport {
|
|||
public String appendIdentitySelectToInsert(String identityColumnName, String insertString) {
|
||||
return "select " + identityColumnName + " from final table ( " + insertString + " )";
|
||||
}
|
||||
|
||||
public void render(
|
||||
TableInsert tableInsert,
|
||||
Consumer<String> sqlAppender,
|
||||
Consumer<ColumnReference> returnColumnHandler,
|
||||
InsertValuesHandler insertValuesHandler,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
// select col(, col)* from final table ( <real insert> )
|
||||
|
||||
sqlAppender.accept( "select " );
|
||||
|
||||
final List<ColumnReference> returningColumns = tableInsert.getReturningColumns();
|
||||
for ( int i = 0; i < returningColumns.size(); i++ ) {
|
||||
if ( i > 0 ) {
|
||||
sqlAppender.accept( ", " );
|
||||
}
|
||||
|
||||
returnColumnHandler.accept( returningColumns.get( i ) );
|
||||
}
|
||||
|
||||
sqlAppender.accept( " from final table ( " );
|
||||
insertValuesHandler.renderInsertValues();
|
||||
sqlAppender.accept( ")" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.dialect.identity;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.model.ast.TableInsert;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
|
@ -36,4 +42,19 @@ public class H2IdentityColumnSupport extends IdentityColumnSupportImpl {
|
|||
public String getIdentityInsertString() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface InsertValuesHandler {
|
||||
void renderInsertValues();
|
||||
}
|
||||
|
||||
public void render(
|
||||
TableInsert tableInsert,
|
||||
Consumer<String> sqlAppender,
|
||||
Consumer<ColumnReference> returnColumnHandler,
|
||||
InsertValuesHandler insertValuesHandler,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
insertValuesHandler.renderInsertValues();
|
||||
sqlAppender.accept( " call identity();" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.dialect.identity;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.insert.GetGeneratedKeysDelegate;
|
||||
|
||||
/**
|
||||
* A set of operations providing support for identity columns
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.dialect.identity;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.insert.GetGeneratedKeysDelegate;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
|
|
|
@ -7,18 +7,20 @@
|
|||
package org.hibernate.dialect.identity;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.insert.GetGeneratedKeysDelegate;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class Oracle12cGetGeneratedKeysDelegate extends GetGeneratedKeysDelegate {
|
||||
private String[] keyColumns;
|
||||
private final String[] keyColumns;
|
||||
|
||||
public Oracle12cGetGeneratedKeysDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
|
||||
super( persister, dialect );
|
||||
|
@ -30,10 +32,9 @@ public class Oracle12cGetGeneratedKeysDelegate extends GetGeneratedKeysDelegate
|
|||
}
|
||||
|
||||
@Override
|
||||
protected PreparedStatement prepare(String insertSQL, SharedSessionContractImplementor session) throws SQLException {
|
||||
return session
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( insertSQL, keyColumns );
|
||||
public PreparedStatement prepareStatement(String insertSql, SharedSessionContractImplementor session) {
|
||||
final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
|
||||
final MutationStatementPreparer statementPreparer = jdbcCoordinator.getMutationStatementPreparer();
|
||||
return statementPreparer.prepareStatement( insertSql, keyColumns );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.dialect.identity;
|
|||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.insert.GetGeneratedKeysDelegate;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
|
|
|
@ -156,11 +156,15 @@ public final class Versioning {
|
|||
if ( hasDirtyCollections ) {
|
||||
return true;
|
||||
}
|
||||
for ( int dirtyProperty : dirtyProperties ) {
|
||||
if ( propertyVersionability[dirtyProperty] ) {
|
||||
return true;
|
||||
|
||||
if ( dirtyProperties != null ) {
|
||||
for ( int dirtyProperty : dirtyProperties ) {
|
||||
if ( propertyVersionability[dirtyProperty] ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.engine.jdbc;
|
||||
|
||||
import org.hibernate.internal.log.SubSystemLogging;
|
||||
|
||||
import org.jboss.logging.BasicLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.logging.annotations.LogMessage;
|
||||
import org.jboss.logging.annotations.Message;
|
||||
import org.jboss.logging.annotations.MessageLogger;
|
||||
import org.jboss.logging.annotations.ValidIdRange;
|
||||
|
||||
import static org.jboss.logging.Logger.Level.WARN;
|
||||
|
||||
/**
|
||||
* Sub-system logging related to JDBC interactions
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SubSystemLogging(
|
||||
name = JdbcLogging.NAME,
|
||||
description = "Logging related to JDBC interactions"
|
||||
)
|
||||
@MessageLogger(projectCode = "HHH")
|
||||
@ValidIdRange(min = 100001, max = 100500)
|
||||
public interface JdbcLogging extends BasicLogger {
|
||||
String NAME = "org.hibernate.orm.jdbc";
|
||||
|
||||
Logger JDBC_LOGGER = Logger.getLogger( NAME );
|
||||
JdbcLogging JDBC_MESSAGE_LOGGER = Logger.getMessageLogger( JdbcLogging.class, NAME );
|
||||
|
||||
boolean JDBC_TRACE_ENABLED = JDBC_LOGGER.isTraceEnabled();
|
||||
boolean JDBC_DEBUG_ENABLED = JDBC_LOGGER.isDebugEnabled();
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(
|
||||
id=100001,
|
||||
value = "JDBC driver did not return the expected number of row counts (%s) - expected %s, but received %s"
|
||||
)
|
||||
void unexpectedRowCounts(String tableName, int expected, int actual);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.engine.jdbc.batch;
|
||||
|
||||
import org.hibernate.internal.log.SubSystemLogging;
|
||||
|
||||
import org.jboss.logging.BasicLogger;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.logging.annotations.LogMessage;
|
||||
import org.jboss.logging.annotations.Message;
|
||||
import org.jboss.logging.annotations.MessageLogger;
|
||||
import org.jboss.logging.annotations.ValidIdRange;
|
||||
|
||||
import static org.jboss.logging.Logger.Level.ERROR;
|
||||
import static org.jboss.logging.Logger.Level.INFO;
|
||||
|
||||
/**
|
||||
* Sub-system logging related to JDBC batch execution
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SubSystemLogging(
|
||||
name = JdbcBatchLogging.NAME,
|
||||
description = "Logging related to JDBC batch execution"
|
||||
)
|
||||
@MessageLogger(projectCode = "HHH")
|
||||
@ValidIdRange(min = 100501, max = 101000)
|
||||
public interface JdbcBatchLogging extends BasicLogger {
|
||||
String NAME = "org.hibernate.orm.jdbc.batch";
|
||||
|
||||
Logger BATCH_LOGGER = Logger.getLogger( NAME );
|
||||
JdbcBatchLogging BATCH_MESSAGE_LOGGER = Logger.getMessageLogger( JdbcBatchLogging.class, NAME );
|
||||
|
||||
boolean BATCH_TRACE_ENABLED = BATCH_LOGGER.isTraceEnabled();
|
||||
boolean BATCH_DEBUG_ENABLED = BATCH_LOGGER.isDebugEnabled();
|
||||
|
||||
@LogMessage(level = ERROR)
|
||||
@Message(id = 100501, value = "Exception executing batch [%s], SQL: %s")
|
||||
void unableToExecuteBatch(Exception e, String sql );
|
||||
|
||||
@LogMessage(level = ERROR)
|
||||
@Message(id = 100502, value = "Unable to release batch statement...")
|
||||
void unableToReleaseBatchStatement();
|
||||
|
||||
@LogMessage(level = INFO)
|
||||
@Message(id=100503, value = "On release of batch it still contained JDBC statements")
|
||||
void batchContainedStatementsOnRelease();
|
||||
}
|
|
@ -1,218 +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.engine.jdbc.batch.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchObserver;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.resource.jdbc.ResourceRegistry;
|
||||
|
||||
/**
|
||||
* Convenience base class for implementers of the Batch interface.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
public abstract class AbstractBatchImpl implements Batch {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
AbstractBatchImpl.class.getName()
|
||||
);
|
||||
|
||||
private final BatchKey key;
|
||||
private final JdbcCoordinator jdbcCoordinator;
|
||||
|
||||
private final SqlStatementLogger sqlStatementLogger;
|
||||
private final SqlExceptionHelper sqlExceptionHelper;
|
||||
|
||||
private final LinkedHashMap<String, PreparedStatement> statements = new LinkedHashMap<>();
|
||||
private final LinkedHashSet<BatchObserver> observers = new LinkedHashSet<>();
|
||||
|
||||
protected AbstractBatchImpl(BatchKey key, JdbcCoordinator jdbcCoordinator) {
|
||||
if ( key == null ) {
|
||||
throw new IllegalArgumentException( "batch key cannot be null" );
|
||||
}
|
||||
if ( jdbcCoordinator == null ) {
|
||||
throw new IllegalArgumentException( "JDBC coordinator cannot be null" );
|
||||
}
|
||||
this.key = key;
|
||||
this.jdbcCoordinator = jdbcCoordinator;
|
||||
|
||||
final JdbcServices jdbcServices = jdbcCoordinator.getJdbcSessionOwner()
|
||||
.getJdbcSessionContext()
|
||||
.getServiceRegistry()
|
||||
.getService( JdbcServices.class );
|
||||
|
||||
this.sqlStatementLogger = jdbcServices.getSqlStatementLogger();
|
||||
this.sqlExceptionHelper = jdbcServices.getSqlExceptionHelper();
|
||||
}
|
||||
|
||||
protected JdbcCoordinator getJdbcCoordinator(){
|
||||
return this.jdbcCoordinator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform batch execution..
|
||||
* <p>
|
||||
* This is called from the explicit {@linkplain #execute() execution}, but may also be called from elsewhere
|
||||
* depending on the exact implementation.
|
||||
*/
|
||||
protected abstract void doExecuteBatch();
|
||||
|
||||
/**
|
||||
* Convenience access to the SQLException helper.
|
||||
*
|
||||
* @return The underlying SQLException helper.
|
||||
*/
|
||||
protected SqlExceptionHelper sqlExceptionHelper() {
|
||||
return sqlExceptionHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience access to the SQL statement logger.
|
||||
*
|
||||
* @return The underlying JDBC services.
|
||||
*/
|
||||
protected SqlStatementLogger sqlStatementLogger() {
|
||||
return sqlStatementLogger;
|
||||
}
|
||||
|
||||
protected void abortBatch(Exception cause) {
|
||||
try {
|
||||
jdbcCoordinator.abortBatch();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
cause.addSuppressed( e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to the batch's map of statements (keyed by SQL statement string).
|
||||
*
|
||||
* @return This batch's statements.
|
||||
*/
|
||||
protected LinkedHashMap<String,PreparedStatement> getStatements() {
|
||||
return statements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BatchKey getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addObserver(BatchObserver observer) {
|
||||
observers.add( observer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement getBatchStatement(String sql, boolean callable) {
|
||||
if ( sql == null ) {
|
||||
throw new IllegalArgumentException( "sql must be non-null." );
|
||||
}
|
||||
PreparedStatement statement = statements.get( sql );
|
||||
if ( statement == null ) {
|
||||
statement = buildBatchStatement( sql, callable );
|
||||
statements.put( sql, statement );
|
||||
}
|
||||
else {
|
||||
LOG.debug( "Reusing batch statement" );
|
||||
sqlStatementLogger().logStatement( sql );
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
private PreparedStatement buildBatchStatement(String sql, boolean callable) {
|
||||
return jdbcCoordinator.getStatementPreparer().prepareStatement( sql, callable );
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute() {
|
||||
notifyObserversExplicitExecution();
|
||||
if ( getStatements().isEmpty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
doExecuteBatch();
|
||||
}
|
||||
finally {
|
||||
releaseStatements();
|
||||
}
|
||||
}
|
||||
|
||||
protected void releaseStatements() {
|
||||
final LinkedHashMap<String, PreparedStatement> statements = getStatements();
|
||||
final ResourceRegistry resourceRegistry = jdbcCoordinator.getLogicalConnection().getResourceRegistry();
|
||||
for ( PreparedStatement statement : statements.values() ) {
|
||||
clearBatch( statement );
|
||||
resourceRegistry.release( statement );
|
||||
}
|
||||
// IMPL NOTE: If the statements are not cleared and JTA is being used, then
|
||||
// jdbcCoordinator.afterStatementExecution() will abort the batch and a
|
||||
// warning will be logged. To avoid the warning, clear statements first,
|
||||
// before calling jdbcCoordinator.afterStatementExecution().
|
||||
statements.clear();
|
||||
jdbcCoordinator.afterStatementExecution();
|
||||
}
|
||||
|
||||
protected void clearBatch(PreparedStatement statement) {
|
||||
try {
|
||||
// This code can be called after the connection is released
|
||||
// and the statement is closed. If the statement is closed,
|
||||
// then SQLException will be thrown when PreparedStatement#clearBatch
|
||||
// is called.
|
||||
// Ensure the statement is not closed before
|
||||
// calling PreparedStatement#clearBatch.
|
||||
if ( !statement.isClosed() ) {
|
||||
statement.clearBatch();
|
||||
}
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
LOG.unableToReleaseBatchStatement();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to notify registered observers of an explicit execution of this batch.
|
||||
*/
|
||||
protected final void notifyObserversExplicitExecution() {
|
||||
for ( BatchObserver observer : observers ) {
|
||||
observer.batchExplicitlyExecuted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to notify registered observers of an implicit execution of this batch.
|
||||
*/
|
||||
protected final void notifyObserversImplicitExecution() {
|
||||
for ( BatchObserver observer : observers ) {
|
||||
observer.batchImplicitlyExecuted();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
if ( getStatements() != null && !getStatements().isEmpty() ) {
|
||||
LOG.batchContainedStatementsOnRelease();
|
||||
}
|
||||
releaseStatements();
|
||||
observers.clear();
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ package org.hibernate.engine.jdbc.batch.internal;
|
|||
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
|
||||
/**
|
||||
* Normal implementation of BatchKey
|
||||
|
@ -19,6 +20,13 @@ public class BasicBatchKey implements BatchKey {
|
|||
private final int statementCount;
|
||||
private final Expectation expectation;
|
||||
|
||||
/**
|
||||
* Constructs a BasicBatchKey with {@link Expectations#NONE}
|
||||
*/
|
||||
public BasicBatchKey(String comparison) {
|
||||
this( comparison, Expectations.NONE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a BasicBatchKey
|
||||
*
|
||||
|
@ -59,4 +67,13 @@ public class BasicBatchKey implements BatchKey {
|
|||
return comparison.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toLoggableString() {
|
||||
return comparison;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BasicBatchKey(" + comparison + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,27 @@
|
|||
* 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>.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.batch.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
import org.hibernate.engine.jdbc.mutation.internal.PreparedStatementGroupSingleTable;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
import org.hibernate.sql.model.jdbc.JdbcInsertMutation;
|
||||
|
||||
import static org.hibernate.engine.jdbc.batch.JdbcBatchLogging.BATCH_LOGGER;
|
||||
import static org.hibernate.engine.jdbc.batch.JdbcBatchLogging.BATCH_TRACE_ENABLED;
|
||||
import static org.hibernate.jdbc.Expectations.NONE;
|
||||
|
||||
/**
|
||||
* A builder for {@link Batch} instances.
|
||||
|
@ -17,35 +30,115 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BatchBuilderImpl implements BatchBuilder {
|
||||
|
||||
private volatile int jdbcBatchSize;
|
||||
|
||||
/**
|
||||
* Constructs a BatchBuilderImpl
|
||||
*/
|
||||
public BatchBuilderImpl() {
|
||||
}
|
||||
private final int globalBatchSize;
|
||||
|
||||
/**
|
||||
* Constructs a BatchBuilderImpl
|
||||
*
|
||||
* @param jdbcBatchSize The batch jdbcBatchSize to use.
|
||||
* @param globalBatchSize The batch size to use. Can be overridden
|
||||
* on {@link #buildBatch}
|
||||
*/
|
||||
public BatchBuilderImpl(int jdbcBatchSize) {
|
||||
this.jdbcBatchSize = jdbcBatchSize;
|
||||
public BatchBuilderImpl(int globalBatchSize) {
|
||||
if ( BATCH_TRACE_ENABLED ) {
|
||||
BATCH_LOGGER.tracef(
|
||||
"Using standard BatchBuilder (%s)",
|
||||
globalBatchSize
|
||||
);
|
||||
}
|
||||
|
||||
this.globalBatchSize = globalBatchSize;
|
||||
}
|
||||
|
||||
public int getJdbcBatchSize() {
|
||||
return jdbcBatchSize;
|
||||
}
|
||||
|
||||
public void setJdbcBatchSize(int jdbcBatchSize) {
|
||||
this.jdbcBatchSize = jdbcBatchSize;
|
||||
return globalBatchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) {
|
||||
return SharedBatchBuildingCode.buildBatch( jdbcBatchSize, key, jdbcCoordinator );
|
||||
public Batch buildBatch(
|
||||
BatchKey key,
|
||||
Integer explicitBatchSize,
|
||||
Supplier<PreparedStatementGroup> statementGroupSupplier,
|
||||
JdbcCoordinator jdbcCoordinator) {
|
||||
final int batchSize = explicitBatchSize == null
|
||||
? globalBatchSize
|
||||
: explicitBatchSize;
|
||||
assert batchSize > 1;
|
||||
|
||||
return new BatchImpl( key, statementGroupSupplier.get(), batchSize, jdbcCoordinator );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Intended for use from tests
|
||||
*/
|
||||
@Internal
|
||||
public BatchImpl buildBatch(BatchKey batchKey, Integer sizeOverride, String table, SessionImplementor session, String sql) {
|
||||
final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
|
||||
|
||||
final int batchSize = sizeOverride == null
|
||||
? globalBatchSize
|
||||
: sizeOverride;
|
||||
|
||||
return new BatchImpl(
|
||||
batchKey,
|
||||
new PreparedStatementGroupSingleTable(
|
||||
new JdbcInsertMutation(
|
||||
new TableMapping() {
|
||||
@Override
|
||||
public String getTableName() {
|
||||
return table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRelativePosition() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptional() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInverse() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIdentifierTable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutationDetails getInsertDetails() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutationDetails getUpdateDetails() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCascadeDeleteEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutationDetails getDeleteDetails() {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
null,
|
||||
sql,
|
||||
false,
|
||||
NONE,
|
||||
Collections.emptyList()
|
||||
),
|
||||
session
|
||||
),
|
||||
batchSize,
|
||||
jdbcCoordinator
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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>.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.batch.internal;
|
||||
|
||||
|
@ -10,6 +10,7 @@ import java.util.Map;
|
|||
|
||||
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
|
@ -29,6 +30,8 @@ public class BatchBuilderInitiator implements StandardServiceInitiator<BatchBuil
|
|||
|
||||
/**
|
||||
* Names the BatchBuilder implementation to use.
|
||||
*
|
||||
* @see AvailableSettings#BATCH_STRATEGY
|
||||
*/
|
||||
public static final String BUILDER = "hibernate.jdbc.batch.builder";
|
||||
|
||||
|
@ -39,7 +42,12 @@ public class BatchBuilderInitiator implements StandardServiceInitiator<BatchBuil
|
|||
|
||||
@Override
|
||||
public BatchBuilder initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
||||
final Object builder = configurationValues.get( BUILDER );
|
||||
Object builder = configurationValues.get( BUILDER );
|
||||
|
||||
if ( builder == null ) {
|
||||
builder = configurationValues.get( AvailableSettings.BATCH_STRATEGY );
|
||||
}
|
||||
|
||||
if ( builder == null ) {
|
||||
return new BatchBuilderImpl(
|
||||
ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, 1 )
|
||||
|
@ -52,7 +60,10 @@ public class BatchBuilderInitiator implements StandardServiceInitiator<BatchBuil
|
|||
|
||||
final String builderClassName = builder.toString();
|
||||
try {
|
||||
return (BatchBuilder) registry.getService( ClassLoaderService.class ).classForName( builderClassName ).newInstance();
|
||||
return (BatchBuilder) registry.getService( ClassLoaderService.class )
|
||||
.classForName( builderClassName )
|
||||
.getConstructor()
|
||||
.newInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new ServiceException( "Could not build explicit BatchBuilder [" + builderClassName + "]", e );
|
||||
|
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* 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.engine.jdbc.batch.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchObserver;
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcObserver;
|
||||
|
||||
import static org.hibernate.engine.jdbc.JdbcLogging.JDBC_MESSAGE_LOGGER;
|
||||
import static org.hibernate.engine.jdbc.batch.JdbcBatchLogging.BATCH_DEBUG_ENABLED;
|
||||
import static org.hibernate.engine.jdbc.batch.JdbcBatchLogging.BATCH_LOGGER;
|
||||
import static org.hibernate.engine.jdbc.batch.JdbcBatchLogging.BATCH_MESSAGE_LOGGER;
|
||||
import static org.hibernate.engine.jdbc.batch.JdbcBatchLogging.BATCH_TRACE_ENABLED;
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER_TRACE_ENABLED;
|
||||
|
||||
/**
|
||||
* Standard implementation of Batch
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BatchImpl implements Batch {
|
||||
private final BatchKey key;
|
||||
private final int batchSizeToUse;
|
||||
private final PreparedStatementGroup statementGroup;
|
||||
|
||||
private final JdbcCoordinator jdbcCoordinator;
|
||||
private final SqlStatementLogger sqlStatementLogger;
|
||||
private final SqlExceptionHelper sqlExceptionHelper;
|
||||
|
||||
private final LinkedHashSet<BatchObserver> observers = new LinkedHashSet<>();
|
||||
|
||||
private int batchPosition;
|
||||
private boolean batchExecuted;
|
||||
|
||||
public BatchImpl(
|
||||
BatchKey key,
|
||||
PreparedStatementGroup statementGroup,
|
||||
int batchSizeToUse,
|
||||
JdbcCoordinator jdbcCoordinator) {
|
||||
if ( key == null ) {
|
||||
throw new IllegalArgumentException( "Batch key cannot be null" );
|
||||
}
|
||||
if ( jdbcCoordinator == null ) {
|
||||
throw new IllegalArgumentException( "JDBC coordinator cannot be null" );
|
||||
}
|
||||
|
||||
this.key = key;
|
||||
this.jdbcCoordinator = jdbcCoordinator;
|
||||
this.statementGroup = statementGroup;
|
||||
|
||||
final JdbcServices jdbcServices = jdbcCoordinator.getJdbcSessionOwner()
|
||||
.getJdbcSessionContext()
|
||||
.getServiceRegistry()
|
||||
.getService( JdbcServices.class );
|
||||
|
||||
this.sqlStatementLogger = jdbcServices.getSqlStatementLogger();
|
||||
this.sqlExceptionHelper = jdbcServices.getSqlExceptionHelper();
|
||||
|
||||
this.batchSizeToUse = batchSizeToUse;
|
||||
|
||||
if ( BATCH_TRACE_ENABLED ) {
|
||||
BATCH_LOGGER.tracef(
|
||||
"Created Batch (%s) - `%s`",
|
||||
batchSizeToUse,
|
||||
key.toLoggableString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BatchKey getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementGroup getStatementGroup() {
|
||||
return statementGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addObserver(BatchObserver observer) {
|
||||
observers.add( observer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToBatch(JdbcValueBindings jdbcValueBindings, TableInclusionChecker inclusionChecker) {
|
||||
if ( BATCH_TRACE_ENABLED ) {
|
||||
BATCH_LOGGER.tracef(
|
||||
"Adding to JDBC batch (%s) - `%s`",
|
||||
batchPosition + 1,
|
||||
getKey().toLoggableString()
|
||||
);
|
||||
}
|
||||
|
||||
final SharedSessionContractImplementor session = (SharedSessionContractImplementor) jdbcCoordinator.getJdbcSessionOwner();
|
||||
|
||||
try {
|
||||
getStatementGroup().forEachStatement( (tableName, statementDetails) -> {
|
||||
if ( inclusionChecker != null && !inclusionChecker.include( statementDetails.getMutatingTableDetails() ) ) {
|
||||
if ( MODEL_MUTATION_LOGGER_TRACE_ENABLED ) {
|
||||
MODEL_MUTATION_LOGGER.tracef(
|
||||
"Skipping addBatch for table : %s (batch-position=%s)",
|
||||
statementDetails.getMutatingTableDetails().getTableName(),
|
||||
batchPosition+1
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//noinspection resource
|
||||
final PreparedStatement statement = statementDetails.resolveStatement();
|
||||
sqlStatementLogger.logStatement( statementDetails.getSqlString() );
|
||||
jdbcValueBindings.beforeStatement( statementDetails, session );
|
||||
|
||||
try {
|
||||
statement.addBatch();
|
||||
}
|
||||
catch (SQLException e) {
|
||||
BATCH_LOGGER.debug( "SQLException escaped proxy", e );
|
||||
throw sqlExceptionHelper.convert(
|
||||
e,
|
||||
"Could not perform addBatch",
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
// todo (mutation) : is this needed?
|
||||
jdbcValueBindings.afterStatement( statementDetails.getMutatingTableDetails(), session );
|
||||
}
|
||||
} );
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
abortBatch( e );
|
||||
throw e;
|
||||
}
|
||||
|
||||
batchPosition++;
|
||||
if ( batchPosition == batchSizeToUse ) {
|
||||
notifyObserversImplicitExecution();
|
||||
performExecution();
|
||||
batchPosition = 0;
|
||||
batchExecuted = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected void releaseStatements() {
|
||||
statementGroup.forEachStatement( (tableName, statementDetails) -> {
|
||||
if ( statementDetails.getStatement() == null ) {
|
||||
BATCH_LOGGER.debugf(
|
||||
"PreparedStatementDetails did not contain PreparedStatement on #releaseStatements : %s",
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
clearBatch( statementDetails );
|
||||
} );
|
||||
|
||||
statementGroup.release();
|
||||
jdbcCoordinator.afterStatementExecution();
|
||||
}
|
||||
|
||||
protected void clearBatch(PreparedStatementDetails statementDetails) {
|
||||
final PreparedStatement statement = statementDetails.getStatement();
|
||||
assert statement != null;
|
||||
|
||||
try {
|
||||
// This code can be called after the connection is released
|
||||
// and the statement is closed. If the statement is closed,
|
||||
// then SQLException will be thrown when PreparedStatement#clearBatch
|
||||
// is called.
|
||||
// Ensure the statement is not closed before
|
||||
// calling PreparedStatement#clearBatch.
|
||||
if ( !statement.isClosed() ) {
|
||||
statement.clearBatch();
|
||||
}
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
BATCH_MESSAGE_LOGGER.unableToReleaseBatchStatement();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to notify registered observers of an explicit execution of this batch.
|
||||
*/
|
||||
protected final void notifyObserversExplicitExecution() {
|
||||
for ( BatchObserver observer : observers ) {
|
||||
observer.batchExplicitlyExecuted();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to notify registered observers of an implicit execution of this batch.
|
||||
*/
|
||||
protected final void notifyObserversImplicitExecution() {
|
||||
for ( BatchObserver observer : observers ) {
|
||||
observer.batchImplicitlyExecuted();
|
||||
}
|
||||
}
|
||||
|
||||
protected void abortBatch(Exception cause) {
|
||||
try {
|
||||
jdbcCoordinator.abortBatch();
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
cause.addSuppressed( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
notifyObserversExplicitExecution();
|
||||
if ( getStatementGroup().getNumberOfStatements() == 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( batchPosition == 0 ) {
|
||||
if( !batchExecuted) {
|
||||
if ( BATCH_DEBUG_ENABLED ) {
|
||||
BATCH_LOGGER.debugf(
|
||||
"No batched statements to execute - %s",
|
||||
getKey().toLoggableString()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
performExecution();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
releaseStatements();
|
||||
}
|
||||
}
|
||||
|
||||
protected void performExecution() {
|
||||
if ( BATCH_TRACE_ENABLED ) {
|
||||
BATCH_LOGGER.tracef(
|
||||
"Executing JDBC batch (%s / %s) - `%s`",
|
||||
batchPosition,
|
||||
batchSizeToUse,
|
||||
getKey().toLoggableString()
|
||||
);
|
||||
}
|
||||
|
||||
//noinspection deprecation
|
||||
final JdbcObserver observer = jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getObserver();
|
||||
try {
|
||||
getStatementGroup().forEachStatement( (tableName, statementDetails) -> {
|
||||
final String sql = statementDetails.getSqlString();
|
||||
final PreparedStatement statement = statementDetails.getStatement();
|
||||
|
||||
if ( statement == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ( statementDetails.getMutatingTableDetails().isIdentifierTable() ) {
|
||||
final int[] rowCounts;
|
||||
try {
|
||||
observer.jdbcExecuteBatchStart();
|
||||
rowCounts = statement.executeBatch();
|
||||
}
|
||||
finally {
|
||||
observer.jdbcExecuteBatchEnd();
|
||||
}
|
||||
checkRowCounts( rowCounts, statementDetails );
|
||||
}
|
||||
else {
|
||||
statement.executeBatch();
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
abortBatch( e );
|
||||
BATCH_MESSAGE_LOGGER.unableToExecuteBatch( e, sql );
|
||||
throw sqlExceptionHelper.convert( e, "could not execute batch", sql );
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
abortBatch( re );
|
||||
BATCH_MESSAGE_LOGGER.unableToExecuteBatch( re, sql );
|
||||
throw re;
|
||||
}
|
||||
} );
|
||||
}
|
||||
finally {
|
||||
batchPosition = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRowCounts(int[] rowCounts, PreparedStatementDetails statementDetails) throws SQLException, HibernateException {
|
||||
final int numberOfRowCounts = rowCounts.length;
|
||||
if ( batchPosition != 0 ) {
|
||||
final int expectedNumberOfCounts = batchPosition / getStatementGroup().getNumberOfStatements();
|
||||
if ( numberOfRowCounts != expectedNumberOfCounts ) {
|
||||
JDBC_MESSAGE_LOGGER.unexpectedRowCounts(
|
||||
statementDetails.getMutatingTableDetails().getTableName(),
|
||||
numberOfRowCounts,
|
||||
expectedNumberOfCounts
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < numberOfRowCounts; i++ ) {
|
||||
statementDetails.getExpectation().verifyOutcome( rowCounts[i], statementDetails.getStatement(), i, statementDetails.getSqlString() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
if ( BATCH_MESSAGE_LOGGER.isInfoEnabled() ) {
|
||||
final PreparedStatementGroup statementGroup = getStatementGroup();
|
||||
if ( statementGroup.getNumberOfStatements() != 0 ) {
|
||||
if ( statementGroup.hasMatching( (statementDetails) -> statementDetails.getStatement() != null ) ) {
|
||||
BATCH_MESSAGE_LOGGER.batchContainedStatementsOnRelease();
|
||||
}
|
||||
}
|
||||
}
|
||||
releaseStatements();
|
||||
observers.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BatchImpl(" + getKey().toLoggableString() + ")";
|
||||
}
|
||||
}
|
|
@ -1,156 +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.engine.jdbc.batch.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
|
||||
import org.hibernate.resource.jdbc.spi.JdbcObserver;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* A {@link org.hibernate.engine.jdbc.batch.spi.Batch} implementation which does bathing based on a given size. Once
|
||||
* the batch size is reached for a statement in the batch, the entire batch is implicitly executed.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BatchingBatch extends AbstractBatchImpl {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
BatchingBatch.class.getName()
|
||||
);
|
||||
|
||||
private int batchSize;
|
||||
private final int configuredBatchSize;
|
||||
private int batchPosition;
|
||||
private boolean batchExecuted;
|
||||
private int statementPosition;
|
||||
|
||||
/**
|
||||
* Constructs a BatchingBatch
|
||||
*
|
||||
* @param key The batch key
|
||||
* @param jdbcCoordinator The JDBC jdbcCoordinator
|
||||
* @param batchSize The batch size.
|
||||
*/
|
||||
public BatchingBatch(
|
||||
BatchKey key,
|
||||
JdbcCoordinator jdbcCoordinator,
|
||||
int batchSize) {
|
||||
super( key, jdbcCoordinator );
|
||||
if ( ! key.getExpectation().canBeBatched() ) {
|
||||
throw new HibernateException( "attempting to batch an operation which cannot be batched" );
|
||||
}
|
||||
this.batchSize = batchSize;
|
||||
this.configuredBatchSize = batchSize;
|
||||
}
|
||||
|
||||
private String currentStatementSql;
|
||||
private PreparedStatement currentStatement;
|
||||
|
||||
@Override
|
||||
public PreparedStatement getBatchStatement(String sql, boolean callable) {
|
||||
currentStatementSql = sql;
|
||||
int previousBatchSize = getStatements().size();
|
||||
currentStatement = super.getBatchStatement( sql, callable );
|
||||
int currentBatchSize = getStatements().size();
|
||||
if ( currentBatchSize > previousBatchSize ) {
|
||||
this.batchSize = this.configuredBatchSize * currentBatchSize;
|
||||
}
|
||||
return currentStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToBatch() {
|
||||
try {
|
||||
currentStatement.addBatch();
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
abortBatch( e );
|
||||
LOG.debug( "SQLException escaped proxy", e );
|
||||
throw sqlExceptionHelper().convert( e, "could not perform addBatch", currentStatementSql );
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
abortBatch( e );
|
||||
throw e;
|
||||
}
|
||||
statementPosition++;
|
||||
if ( statementPosition >= getKey().getBatchedStatementCount() ) {
|
||||
batchPosition++;
|
||||
if ( batchPosition == batchSize ) {
|
||||
notifyObserversImplicitExecution();
|
||||
performExecution();
|
||||
batchPosition = 0;
|
||||
batchExecuted = true;
|
||||
}
|
||||
statementPosition = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecuteBatch() {
|
||||
if (batchPosition == 0 ) {
|
||||
if(! batchExecuted) {
|
||||
LOG.debug( "No batched statements to execute" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
performExecution();
|
||||
}
|
||||
}
|
||||
|
||||
private void performExecution() {
|
||||
LOG.debugf( "Executing batch size: %s", batchPosition );
|
||||
final JdbcObserver observer = getJdbcCoordinator().getJdbcSessionOwner().getJdbcSessionContext().getObserver();
|
||||
try {
|
||||
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
|
||||
final String sql = entry.getKey();
|
||||
try {
|
||||
final PreparedStatement statement = entry.getValue();
|
||||
final int[] rowCounts;
|
||||
try {
|
||||
observer.jdbcExecuteBatchStart();
|
||||
rowCounts = statement.executeBatch();
|
||||
}
|
||||
finally {
|
||||
observer.jdbcExecuteBatchEnd();
|
||||
}
|
||||
checkRowCounts( rowCounts, statement, sql );
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
abortBatch( e );
|
||||
LOG.unableToExecuteBatch( e, sql );
|
||||
throw sqlExceptionHelper().convert( e, "could not execute batch", sql );
|
||||
}
|
||||
catch ( RuntimeException re ) {
|
||||
abortBatch( re );
|
||||
LOG.unableToExecuteBatch( re, sql );
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
batchPosition = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRowCounts(int[] rowCounts, PreparedStatement ps, String statementSQL) throws SQLException, HibernateException {
|
||||
final int numberOfRowCounts = rowCounts.length;
|
||||
if ( batchPosition != 0 && numberOfRowCounts != batchPosition / getStatements().size() ) {
|
||||
LOG.unexpectedRowCounts();
|
||||
}
|
||||
for ( int i = 0; i < numberOfRowCounts; i++ ) {
|
||||
getKey().getExpectation().verifyOutcome( rowCounts[i], ps, i, statementSQL );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +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.engine.jdbc.batch.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
|
||||
/**
|
||||
* An implementation of {@link org.hibernate.engine.jdbc.batch.spi.Batch} which does not perform batching. It simply
|
||||
* executes each statement as it is encountered.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NonBatchingBatch extends AbstractBatchImpl {
|
||||
|
||||
private final JdbcCoordinator jdbcCoordinator;
|
||||
|
||||
protected NonBatchingBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) {
|
||||
super( key, jdbcCoordinator );
|
||||
this.jdbcCoordinator = jdbcCoordinator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToBatch() {
|
||||
notifyObserversImplicitExecution();
|
||||
for ( Map.Entry<String,PreparedStatement> entry : getStatements().entrySet() ) {
|
||||
final String statementSQL = entry.getKey();
|
||||
try {
|
||||
final PreparedStatement statement = entry.getValue();
|
||||
final int rowCount = jdbcCoordinator.getResultSetReturn().executeUpdate( statement );
|
||||
getKey().getExpectation().verifyOutcome( rowCount, statement, 0, statementSQL );
|
||||
jdbcCoordinator.getLogicalConnection().getResourceRegistry().release( statement );
|
||||
jdbcCoordinator.afterStatementExecution();
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
abortBatch( e );
|
||||
throw sqlExceptionHelper().convert( e, "could not execute non-batched batch statement", statementSQL );
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
abortBatch( e );
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
getStatements().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void clearBatch(PreparedStatement statement) {
|
||||
// no need to call PreparedStatement#clearBatch here...
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecuteBatch() {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
|
@ -1,28 +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.engine.jdbc.batch.internal;
|
||||
|
||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
|
||||
/**
|
||||
* Common code across BatchBuilder service implementors
|
||||
*/
|
||||
final class SharedBatchBuildingCode {
|
||||
|
||||
static Batch buildBatch(final int defaultJdbcBatchSize, final BatchKey key, final JdbcCoordinator jdbcCoordinator) {
|
||||
final Integer sessionJdbcBatchSize = jdbcCoordinator.getJdbcSessionOwner()
|
||||
.getJdbcBatchSize();
|
||||
final int jdbcBatchSizeToUse = sessionJdbcBatchSize == null ?
|
||||
defaultJdbcBatchSize :
|
||||
sessionJdbcBatchSize;
|
||||
return jdbcBatchSizeToUse > 1
|
||||
? new BatchingBatch( key, jdbcCoordinator, jdbcBatchSizeToUse )
|
||||
: new NonBatchingBatch( key, jdbcCoordinator );
|
||||
}
|
||||
}
|
|
@ -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.engine.jdbc.batch.internal;
|
||||
|
||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
|
||||
/**
|
||||
* Simplified version of BatchBuilderImpl which does not support
|
||||
* changing the configured jdbc Batch size at runtime and is
|
||||
* not exposed via JMX.
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
final class UnmodifiableBatchBuilderImpl implements BatchBuilder {
|
||||
|
||||
private final int jdbcBatchSize;
|
||||
|
||||
public UnmodifiableBatchBuilderImpl(int jdbcBatchSize) {
|
||||
this.jdbcBatchSize = jdbcBatchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) {
|
||||
return SharedBatchBuildingCode.buildBatch( jdbcBatchSize, key, jdbcCoordinator );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,51 +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.engine.jdbc.batch.internal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.service.spi.ServiceException;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
/**
|
||||
* Initiator for the {@link UnmodifiableBatchBuilderImpl} service using
|
||||
* {@link UnmodifiableBatchBuilderImpl}.
|
||||
* This is not the default implementation, but it's a useful alternative to have
|
||||
* in some environments.
|
||||
*
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
public final class UnmodifiableBatchBuilderInitiator implements StandardServiceInitiator<BatchBuilder> {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final UnmodifiableBatchBuilderInitiator INSTANCE = new UnmodifiableBatchBuilderInitiator();
|
||||
|
||||
@Override
|
||||
public Class<BatchBuilder> getServiceInitiated() {
|
||||
return BatchBuilder.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatchBuilder initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
||||
final Object builder = configurationValues.get( BatchBuilderInitiator.BUILDER );
|
||||
if ( builder == null ) {
|
||||
return new UnmodifiableBatchBuilderImpl(
|
||||
ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, 1 )
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new ServiceException( "This Hibernate ORM serviceregistry has been configured explicitly to use " + this.getClass() +
|
||||
" to create BatchBuilder instances; the property '" + BatchBuilderInitiator.BUILDER
|
||||
+ "' is not supported." );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,20 +2,27 @@
|
|||
* 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>.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.batch.spi;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
|
||||
/**
|
||||
* Conceptually models a batch.
|
||||
* <p>
|
||||
* Unlike directly in JDBC, here we add the ability to batch together multiple statements at a time. In the underlying
|
||||
* <p/>
|
||||
* Unlike in JDBC, here we add the ability to batch together multiple statements at a time. In the underlying
|
||||
* JDBC this correlates to multiple {@link PreparedStatement} objects (one for each DML string) maintained within the
|
||||
* batch.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface Batch {
|
||||
/**
|
||||
* Retrieves the object being used to key (uniquely identify) this batch.
|
||||
|
@ -31,20 +38,14 @@ public interface Batch {
|
|||
*/
|
||||
void addObserver(BatchObserver observer);
|
||||
|
||||
/**
|
||||
* Get a statement which is part of the batch, creating if necessary (and storing for next time).
|
||||
*
|
||||
* @param sql The SQL statement.
|
||||
* @param callable Is the SQL statement callable?
|
||||
*
|
||||
* @return The prepared statement instance, representing the SQL statement.
|
||||
*/
|
||||
PreparedStatement getBatchStatement(String sql, boolean callable);
|
||||
PreparedStatementGroup getStatementGroup();
|
||||
|
||||
/**
|
||||
* Apply the value bindings to the batch JDBC statements
|
||||
* and
|
||||
* Indicates completion of the current part of the batch.
|
||||
*/
|
||||
void addToBatch();
|
||||
void addToBatch(JdbcValueBindings jdbcValueBindings, TableInclusionChecker inclusionChecker);
|
||||
|
||||
/**
|
||||
* Execute this batch.
|
||||
|
|
|
@ -2,10 +2,14 @@
|
|||
* 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>.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.batch.spi;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.service.Service;
|
||||
|
||||
|
@ -17,14 +21,14 @@ import org.hibernate.service.Service;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface BatchBuilder extends Service {
|
||||
/**
|
||||
* Build a batch.
|
||||
*
|
||||
* @param key Value to uniquely identify a batch
|
||||
* @param jdbcCoordinator The JDBC coordinator with which to coordinate efforts
|
||||
*
|
||||
* @return The built batch
|
||||
*/
|
||||
Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator);
|
||||
Batch buildBatch(
|
||||
BatchKey key,
|
||||
Integer batchSize,
|
||||
Supplier<PreparedStatementGroup> statementGroupSupplier,
|
||||
JdbcCoordinator jdbcCoordinator);
|
||||
}
|
||||
|
|
|
@ -20,13 +20,23 @@ public interface BatchKey {
|
|||
* Note that this is distinctly different than the size of the batch.
|
||||
*
|
||||
* @return The number of statements.
|
||||
*
|
||||
* @deprecated With no replacement. No longer used
|
||||
*/
|
||||
@Deprecated
|
||||
int getBatchedStatementCount();
|
||||
|
||||
/**
|
||||
* Get the expectation pertaining to the outcome of the {@link Batch} associated with this key.
|
||||
*
|
||||
* @return The expectations
|
||||
*
|
||||
* @deprecated With no replacement. No longer used
|
||||
*/
|
||||
@Deprecated
|
||||
Expectation getExpectation();
|
||||
|
||||
default String toLoggableString() {
|
||||
return toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.sql.Connection;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -21,10 +22,12 @@ import org.hibernate.engine.jdbc.batch.spi.Batch;
|
|||
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
import org.hibernate.engine.jdbc.spi.InvalidatableWrapper;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcWrapper;
|
||||
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
|
||||
import org.hibernate.engine.jdbc.spi.ResultSetReturn;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.engine.jdbc.spi.StatementPreparer;
|
||||
|
@ -120,10 +123,6 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
|||
return this.owner.getJdbcSessionContext().getSessionFactory();
|
||||
}
|
||||
|
||||
protected BatchBuilder batchBuilder() {
|
||||
return sessionFactory().getServiceRegistry().getService( BatchBuilder.class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to the SqlExceptionHelper
|
||||
*
|
||||
|
@ -173,7 +172,7 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Batch getBatch(BatchKey key) {
|
||||
public Batch getBatch2(BatchKey key, Integer batchSize, Supplier<PreparedStatementGroup> statementGroupSupplier) {
|
||||
if ( currentBatch != null ) {
|
||||
if ( currentBatch.getKey().equals( key ) ) {
|
||||
return currentBatch;
|
||||
|
@ -183,16 +182,22 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
|||
currentBatch.release();
|
||||
}
|
||||
}
|
||||
currentBatch = batchBuilder().buildBatch( key, this );
|
||||
|
||||
final BatchBuilder batchBuilder = sessionFactory().getServiceRegistry().getService( BatchBuilder.class );
|
||||
currentBatch = batchBuilder.buildBatch( key, batchSize, statementGroupSupplier, this );
|
||||
|
||||
return currentBatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeBatch() {
|
||||
if ( currentBatch != null ) {
|
||||
currentBatch.execute();
|
||||
// needed?
|
||||
currentBatch.release();
|
||||
try {
|
||||
currentBatch.execute();
|
||||
}
|
||||
finally {
|
||||
currentBatch.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,6 +218,16 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
|||
return statementPreparer;
|
||||
}
|
||||
|
||||
private transient MutationStatementPreparer mutationStatementPreparer;
|
||||
|
||||
@Override
|
||||
public MutationStatementPreparer getMutationStatementPreparer() {
|
||||
if ( mutationStatementPreparer == null ) {
|
||||
mutationStatementPreparer = new MutationStatementPreparerImpl( this, jdbcServices );
|
||||
}
|
||||
return mutationStatementPreparer;
|
||||
}
|
||||
|
||||
private transient ResultSetReturn resultSetExtractor;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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.engine.jdbc.internal;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
|
||||
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
|
||||
import org.hibernate.resource.jdbc.spi.JdbcObserver;
|
||||
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationStatementPreparerImpl implements MutationStatementPreparer {
|
||||
private final JdbcCoordinatorImpl jdbcCoordinator;
|
||||
private final JdbcServices jdbcServices;
|
||||
|
||||
public MutationStatementPreparerImpl(JdbcCoordinatorImpl jdbcCoordinator, JdbcServices jdbcServices) {
|
||||
this.jdbcCoordinator = jdbcCoordinator;
|
||||
this.jdbcServices = jdbcServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, boolean isCallable) {
|
||||
return buildPreparedStatementPreparationTemplate( sql, isCallable ).prepareStatement();
|
||||
}
|
||||
|
||||
private StatementPreparationTemplate buildPreparedStatementPreparationTemplate(String sql, final boolean isCallable) {
|
||||
return new StatementPreparationTemplate( sql ) {
|
||||
@Override
|
||||
protected PreparedStatement doPrepare() throws SQLException {
|
||||
//noinspection resource
|
||||
return isCallable
|
||||
? connection().prepareCall( sql )
|
||||
: connection().prepareStatement( sql );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) {
|
||||
if ( autoGeneratedKeys == PreparedStatement.RETURN_GENERATED_KEYS ) {
|
||||
checkAutoGeneratedKeysSupportEnabled();
|
||||
}
|
||||
return new StatementPreparationTemplate( sql ) {
|
||||
public PreparedStatement doPrepare() throws SQLException {
|
||||
//noinspection resource
|
||||
return connection().prepareStatement( sql, autoGeneratedKeys );
|
||||
}
|
||||
}.prepareStatement();
|
||||
}
|
||||
|
||||
private void checkAutoGeneratedKeysSupportEnabled() {
|
||||
if ( ! settings().isGetGeneratedKeysEnabled() ) {
|
||||
throw new AssertionFailure( "getGeneratedKeys() support is not enabled" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames) {
|
||||
checkAutoGeneratedKeysSupportEnabled();
|
||||
return new StatementPreparationTemplate( sql ) {
|
||||
public PreparedStatement doPrepare() throws SQLException {
|
||||
//noinspection resource
|
||||
return connection().prepareStatement( sql, columnNames );
|
||||
}
|
||||
}.prepareStatement();
|
||||
}
|
||||
|
||||
private abstract class StatementPreparationTemplate {
|
||||
protected final String sql;
|
||||
|
||||
protected StatementPreparationTemplate(String incomingSql) {
|
||||
final String inspectedSql = jdbcCoordinator.getJdbcSessionOwner()
|
||||
.getJdbcSessionContext()
|
||||
.getStatementInspector()
|
||||
.inspect( incomingSql );
|
||||
this.sql = inspectedSql == null ? incomingSql : inspectedSql;
|
||||
}
|
||||
|
||||
public PreparedStatement prepareStatement() {
|
||||
try {
|
||||
final PreparedStatement preparedStatement;
|
||||
//noinspection deprecation
|
||||
final JdbcObserver observer = jdbcCoordinator.getJdbcSessionOwner()
|
||||
.getJdbcSessionContext()
|
||||
.getObserver();
|
||||
try {
|
||||
observer.jdbcPrepareStatementStart();
|
||||
preparedStatement = doPrepare();
|
||||
setStatementTimeout( preparedStatement );
|
||||
}
|
||||
finally {
|
||||
observer.jdbcPrepareStatementEnd();
|
||||
}
|
||||
postProcess( preparedStatement );
|
||||
return preparedStatement;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw sqlExceptionHelper().convert( e, "could not prepare statement", sql );
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract PreparedStatement doPrepare() throws SQLException;
|
||||
|
||||
public void postProcess(PreparedStatement preparedStatement) throws SQLException {
|
||||
jdbcCoordinator.getLogicalConnection().getResourceRegistry().register( preparedStatement, true );
|
||||
// logicalConnection().notifyObserversStatementPrepared();
|
||||
}
|
||||
|
||||
private void setStatementTimeout(PreparedStatement preparedStatement) throws SQLException {
|
||||
final int remainingTransactionTimeOutPeriod = jdbcCoordinator.determineRemainingTransactionTimeOutPeriod();
|
||||
if ( remainingTransactionTimeOutPeriod > 0 ) {
|
||||
preparedStatement.setQueryTimeout( remainingTransactionTimeOutPeriod );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final Connection connection() {
|
||||
return logicalConnection().getPhysicalConnection();
|
||||
}
|
||||
|
||||
protected final LogicalConnectionImplementor logicalConnection() {
|
||||
return jdbcCoordinator.getLogicalConnection();
|
||||
}
|
||||
|
||||
protected final SqlExceptionHelper sqlExceptionHelper() {
|
||||
return jdbcServices.getSqlExceptionHelper();
|
||||
}
|
||||
|
||||
protected final SessionFactoryOptions settings() {
|
||||
//noinspection resource
|
||||
return jdbcCoordinator.sessionFactory().getSessionFactoryOptions();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.mutation.spi.BindingGroup;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
|
||||
/**
|
||||
* The JDBC values for a mutation
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface JdbcValueBindings {
|
||||
/**
|
||||
* Get the bindings for the specific table, or {@code null}
|
||||
*/
|
||||
BindingGroup getBindingGroup(String tableName);
|
||||
|
||||
/**
|
||||
* Binds a value for a specific column+usage
|
||||
*/
|
||||
void bindValue(
|
||||
Object value,
|
||||
String tableName,
|
||||
String columnName,
|
||||
ParameterUsage usage,
|
||||
SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Binds a value for a specific column+usage
|
||||
*/
|
||||
default void bindValue(
|
||||
Object value,
|
||||
SelectableMapping selectableMapping,
|
||||
ParameterUsage usage,
|
||||
SharedSessionContractImplementor session) {
|
||||
bindValue( value, selectableMapping.getContainingTableExpression(), selectableMapping.getSelectionExpression(), usage, session );
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the execution of the operation for the specified table
|
||||
*/
|
||||
void beforeStatement(PreparedStatementDetails statementDetails, SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Called after the execution of the operation for the specified table
|
||||
*/
|
||||
void afterStatement(TableMapping mutatingTable, SharedSessionContractImplementor session);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
|
||||
/**
|
||||
* Main contract for performing the mutation. Accounts for various
|
||||
* moving parts such as:<ul>
|
||||
* <li>Should the statements be batched or not?</li>
|
||||
* <li>Should we "logically" group logging of the parameter bindings?</li>
|
||||
* <li>...</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface MutationExecutor {
|
||||
/**
|
||||
* Get the delegate to be used to coordinate JDBC parameter binding.
|
||||
*/
|
||||
JdbcValueBindings getJdbcValueBindings();
|
||||
|
||||
/**
|
||||
* Details about the {@link java.sql.PreparedStatement} for mutating
|
||||
* the given table.
|
||||
*/
|
||||
PreparedStatementDetails getPreparedStatementDetails(String tableName);
|
||||
|
||||
/**
|
||||
* Perform the execution, returning any generated value.
|
||||
*
|
||||
* @param inclusionChecker The ability to skip the execution for a
|
||||
* specific table; passing {@code null} indicates no filtering
|
||||
* @param resultChecker Custom result checking; pass {@code null} to perform
|
||||
* the standard check using the statement's {@linkplain org.hibernate.jdbc.Expectation expectation}
|
||||
*/
|
||||
Object execute(
|
||||
Object modelReference,
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session);
|
||||
|
||||
void release();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
|
||||
/**
|
||||
* Used to check the results of a statement execution
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
@FunctionalInterface
|
||||
public interface OperationResultChecker {
|
||||
/**
|
||||
* Check the result of a JDBC operation
|
||||
*
|
||||
* @param statementDetails Details for the SQL statement executed
|
||||
* @param affectedRowCount The number of rows affected by the operation, as reported by the JDBC driver
|
||||
* @param batchPosition The execution's position within the active batch, if one; if not batching, -1 will be passed
|
||||
*
|
||||
* @return {@code true} indicates an execution that is considered successful; {@code false} indicates unsuccessful
|
||||
*/
|
||||
boolean checkResult(PreparedStatementDetails statementDetails, int affectedRowCount, int batchPosition) throws SQLException;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.mutation;
|
||||
|
||||
/**
|
||||
* Describes how a parameter is used in a mutation statement
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public enum ParameterUsage {
|
||||
/**
|
||||
* The parameter is used in the update set clause or insert values clause
|
||||
*/
|
||||
SET,
|
||||
|
||||
/**
|
||||
* The parameter is used in the where clause
|
||||
*/
|
||||
RESTRICT
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation;
|
||||
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
|
||||
/**
|
||||
* Used to check if a table should be included in the current execution
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TableInclusionChecker {
|
||||
/**
|
||||
* Perform the check
|
||||
*
|
||||
* @return {@code true} indicates the table should be included;
|
||||
* {@code false} indicates it should not
|
||||
*/
|
||||
boolean include(TableMapping tableMapping);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.group;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
|
||||
/**
|
||||
* Descriptor for details about a {@link PreparedStatement}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface PreparedStatementDetails {
|
||||
/**
|
||||
* The name of the mutating table
|
||||
*/
|
||||
TableMapping getMutatingTableDetails();
|
||||
|
||||
/**
|
||||
* The SQL used to mutate the table
|
||||
*/
|
||||
String getSqlString();
|
||||
|
||||
/**
|
||||
* The {@link PreparedStatement} generated from the SQL. May return null.
|
||||
*
|
||||
* @see #resolveStatement()
|
||||
*/
|
||||
PreparedStatement getStatement();
|
||||
|
||||
/**
|
||||
* The {@link PreparedStatement} generated from the SQL.
|
||||
* <p/>
|
||||
* Unlike {@link #getStatement()}, this method will attempt to create the PreparedStatement
|
||||
*/
|
||||
PreparedStatement resolveStatement();
|
||||
|
||||
/**
|
||||
* The expectation used to validate the outcome of the execution
|
||||
*/
|
||||
Expectation getExpectation();
|
||||
|
||||
/**
|
||||
* Whether the statement is callable
|
||||
*/
|
||||
default boolean isCallable() {
|
||||
return getStatement() instanceof CallableStatement;
|
||||
}
|
||||
|
||||
void releaseStatement(SharedSessionContractImplementor session);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.group;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
|
||||
/**
|
||||
* Grouping of {@link java.sql.PreparedStatement} references
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public interface PreparedStatementGroup {
|
||||
/**
|
||||
* The number of statements in this group
|
||||
*/
|
||||
int getNumberOfStatements();
|
||||
|
||||
int getNumberOfActiveStatements();
|
||||
|
||||
/**
|
||||
* Get the single statement details.
|
||||
*
|
||||
* @throws IllegalStateException if there is more than one statement
|
||||
* associated with this group.
|
||||
*/
|
||||
PreparedStatementDetails getSingleStatementDetails();
|
||||
|
||||
/**
|
||||
* Visit the details for each table mutation
|
||||
*/
|
||||
void forEachStatement(BiConsumer<String, PreparedStatementDetails> action);
|
||||
|
||||
/**
|
||||
* Get the PreparedStatement in this group related to the given table-name.
|
||||
* If the descriptor does not already exist, this method will create it.
|
||||
*
|
||||
* @see #getPreparedStatementDetails
|
||||
*/
|
||||
PreparedStatementDetails resolvePreparedStatementDetails(String tableName);
|
||||
|
||||
/**
|
||||
* Get the PreparedStatement in this group related to the given table-name.
|
||||
* Will return null if no descriptor (yet) exists
|
||||
*/
|
||||
PreparedStatementDetails getPreparedStatementDetails(String tableName);
|
||||
|
||||
/**
|
||||
* Release resources held by this group.
|
||||
*/
|
||||
void release();
|
||||
|
||||
boolean hasMatching(Predicate<PreparedStatementDetails> filter);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.group;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.sql.model.MutationTarget;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
|
||||
/**
|
||||
* Indicates an attempt to access the parameter for an unknown column
|
||||
*
|
||||
* @see org.hibernate.sql.model.MutationOperation#getJdbcValueDescriptor(String, ParameterUsage)
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class UnknownParameterException extends HibernateException {
|
||||
private final MutationType mutationType;
|
||||
private final MutationTarget<?> mutationTarget;
|
||||
private final String tableName;
|
||||
private final String columnName;
|
||||
private final ParameterUsage usage;
|
||||
|
||||
public UnknownParameterException(
|
||||
MutationType mutationType,
|
||||
MutationTarget<?> mutationTarget,
|
||||
String tableName,
|
||||
String columnName,
|
||||
ParameterUsage usage) {
|
||||
super( String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to locate parameter `%s.%s` for %s - %s : %s",
|
||||
tableName,
|
||||
columnName,
|
||||
usage,
|
||||
mutationType.name(),
|
||||
mutationTarget.getRolePath()
|
||||
) );
|
||||
this.mutationType = mutationType;
|
||||
this.mutationTarget = mutationTarget;
|
||||
this.tableName = tableName;
|
||||
this.columnName = columnName;
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
Locale.ROOT,
|
||||
"UnknownParameterException(`%s.%s` for %s - %s : %s)",
|
||||
tableName,
|
||||
columnName,
|
||||
usage,
|
||||
mutationType.name(),
|
||||
StringHelper.collapse( mutationTarget.getRolePath() )
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
|
||||
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER_TRACE_ENABLED;
|
||||
|
||||
/**
|
||||
* Base support for MutationExecutor implementations
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractMutationExecutor implements MutationExecutor {
|
||||
/**
|
||||
* Templated implementation of execution as <ol>
|
||||
* <li>{@link #performNonBatchedOperations}</li>
|
||||
* <li>{@link #performSelfExecutingOperations}</li>
|
||||
* <li>{@link #performBatchedOperations}</li>
|
||||
* </ol>
|
||||
*/
|
||||
@Override
|
||||
public final Object execute(
|
||||
Object modelReference,
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
performNonBatchedOperations( valuesAnalysis, inclusionChecker, resultChecker, session );
|
||||
performSelfExecutingOperations( valuesAnalysis, inclusionChecker, session );
|
||||
performBatchedOperations( valuesAnalysis, inclusionChecker );
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void performNonBatchedOperations(
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
}
|
||||
|
||||
protected void performSelfExecutingOperations(
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
}
|
||||
|
||||
protected void performBatchedOperations(
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a non-batched mutation
|
||||
*/
|
||||
protected void performNonBatchedMutation(
|
||||
PreparedStatementDetails statementDetails,
|
||||
JdbcValueBindings valueBindings,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( statementDetails == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final TableMapping tableDetails = statementDetails.getMutatingTableDetails();
|
||||
if ( inclusionChecker != null && !inclusionChecker.include( tableDetails ) ) {
|
||||
if ( MODEL_MUTATION_LOGGER_TRACE_ENABLED ) {
|
||||
MODEL_MUTATION_LOGGER.tracef(
|
||||
"Skipping execution of secondary insert : %s",
|
||||
tableDetails.getTableName()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get here the statement is needed - make sure it is resolved
|
||||
session.getJdbcServices().getSqlStatementLogger().logStatement( statementDetails.getSqlString() );
|
||||
valueBindings.beforeStatement( statementDetails, session );
|
||||
|
||||
try {
|
||||
final int affectedRowCount = session.getJdbcCoordinator()
|
||||
.getResultSetReturn()
|
||||
.executeUpdate( statementDetails.getStatement() );
|
||||
|
||||
if ( affectedRowCount == 0 && tableDetails.isOptional() ) {
|
||||
// the optional table did not have a row
|
||||
return;
|
||||
}
|
||||
|
||||
ModelMutationHelper.checkResults( resultChecker, statementDetails, affectedRowCount, -1 );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw session.getJdbcServices().getSqlExceptionHelper().convert(
|
||||
e,
|
||||
String.format(
|
||||
"Unable to execute mutation PreparedStatement against table `%s`",
|
||||
tableDetails.getTableName()
|
||||
),
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
}
|
||||
finally {
|
||||
if ( statementDetails.getStatement() != null ) {
|
||||
statementDetails.releaseStatement( session );
|
||||
}
|
||||
valueBindings.afterStatement( tableDetails, session );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||
import org.hibernate.sql.model.jdbc.JdbcValueDescriptor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractSingleMutationExecutor extends AbstractMutationExecutor {
|
||||
private final PreparableMutationOperation mutationOperation;
|
||||
private final JdbcValueBindingsImpl valueBindings;
|
||||
|
||||
public AbstractSingleMutationExecutor(PreparableMutationOperation mutationOperation) {
|
||||
this.mutationOperation = mutationOperation;
|
||||
this.valueBindings = new JdbcValueBindingsImpl(
|
||||
mutationOperation.getMutationType(),
|
||||
mutationOperation.getMutationTarget(),
|
||||
this::findJdbcValueDescriptor
|
||||
);
|
||||
}
|
||||
|
||||
protected PreparableMutationOperation getMutationOperation() {
|
||||
return mutationOperation;
|
||||
}
|
||||
|
||||
protected abstract PreparedStatementGroupSingleTable getStatementGroup();
|
||||
|
||||
@Override
|
||||
public PreparedStatementDetails getPreparedStatementDetails(String tableName) {
|
||||
final PreparedStatementDetails statementDetails = getStatementGroup().getSingleStatementDetails();
|
||||
assert statementDetails.getMutatingTableDetails().getTableName().equals( tableName );
|
||||
return statementDetails;
|
||||
}
|
||||
|
||||
private JdbcValueDescriptor findJdbcValueDescriptor(String tableName, String columnName, ParameterUsage usage) {
|
||||
assert mutationOperation.getTableDetails().getTableName().equals( tableName )
|
||||
: String.format( Locale.ROOT, "table names did not match : `%s` & `%s`", tableName, mutationOperation.getTableDetails().getTableName() );
|
||||
return mutationOperation.findValueDescriptor( columnName, usage );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcValueBindings getJdbcValueBindings() {
|
||||
return valueBindings;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.mutation.group.UnknownParameterException;
|
||||
import org.hibernate.engine.jdbc.mutation.spi.BindingGroup;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.model.MutationTarget;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
import org.hibernate.sql.model.jdbc.JdbcValueDescriptor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcValueBindingsImpl implements JdbcValueBindings {
|
||||
private final MutationType mutationType;
|
||||
private final MutationTarget<?> mutationTarget;
|
||||
private final JdbcValueDescriptorAccess jdbcValueDescriptorAccess;
|
||||
|
||||
private final Map<String, BindingGroup> bindingGroupMap = new HashMap<>();
|
||||
|
||||
public JdbcValueBindingsImpl(
|
||||
MutationType mutationType,
|
||||
MutationTarget<?> mutationTarget,
|
||||
JdbcValueDescriptorAccess jdbcValueDescriptorAccess) {
|
||||
this.mutationType = mutationType;
|
||||
this.mutationTarget = mutationTarget;
|
||||
this.jdbcValueDescriptorAccess = jdbcValueDescriptorAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindingGroup getBindingGroup(String tableName) {
|
||||
return bindingGroupMap.get( tableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindValue(
|
||||
Object value,
|
||||
String tableName,
|
||||
String columnName,
|
||||
ParameterUsage usage,
|
||||
SharedSessionContractImplementor session) {
|
||||
final JdbcValueDescriptor jdbcValueDescriptor = jdbcValueDescriptorAccess.resolveValueDescriptor( tableName, columnName, usage );
|
||||
if ( jdbcValueDescriptor == null ) {
|
||||
throw new UnknownParameterException( mutationType, mutationTarget, tableName, columnName, usage );
|
||||
}
|
||||
|
||||
resolveBindingGroup( tableName ).bindValue( columnName, value, jdbcValueDescriptor );
|
||||
}
|
||||
|
||||
private BindingGroup resolveBindingGroup(String tableName) {
|
||||
final BindingGroup existing = bindingGroupMap.get( tableName );
|
||||
if ( existing != null ) {
|
||||
assert tableName.equals( existing.getTableName() );
|
||||
return existing;
|
||||
}
|
||||
|
||||
final BindingGroup created = new BindingGroup( tableName );
|
||||
bindingGroupMap.put( tableName, created );
|
||||
return created;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeStatement(
|
||||
PreparedStatementDetails statementDetails,
|
||||
SharedSessionContractImplementor session) {
|
||||
final BindingGroup bindingGroup = bindingGroupMap.get( statementDetails.getMutatingTableDetails().getTableName() );
|
||||
if ( bindingGroup == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bindingGroup.forEachBinding( (binding) -> {
|
||||
try {
|
||||
binding.getValueBinder().bind(
|
||||
statementDetails.resolveStatement(),
|
||||
binding.getValue(),
|
||||
binding.getPosition(),
|
||||
session
|
||||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw session.getJdbcServices().getSqlExceptionHelper().convert(
|
||||
e,
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unable to bind parameter #%s - %s",
|
||||
binding.getPosition(),
|
||||
binding.getValue()
|
||||
)
|
||||
);
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterStatement(
|
||||
TableMapping mutatingTable,
|
||||
SharedSessionContractImplementor session) {
|
||||
final BindingGroup bindingGroup = bindingGroupMap.remove( mutatingTable.getTableName() );
|
||||
if ( bindingGroup == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
bindingGroup.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to {@link JdbcValueDescriptor} values
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface JdbcValueDescriptorAccess {
|
||||
JdbcValueDescriptor resolveValueDescriptor(String tableName, String columnName, ParameterUsage usage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
|
||||
import org.hibernate.sql.model.ast.ColumnValueParameter;
|
||||
import org.hibernate.sql.model.jdbc.JdbcValueDescriptor;
|
||||
|
||||
/**
|
||||
* Standard JdbcValueDescriptor implementation
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcValueDescriptorImpl implements JdbcValueDescriptor {
|
||||
private final String columnName;
|
||||
private final ParameterUsage usage;
|
||||
private final JdbcMapping jdbcMapping;
|
||||
private final int jdbcPosition;
|
||||
|
||||
public JdbcValueDescriptorImpl(JdbcParameterBinder jdbcParameterBinder, int jdbcPosition) {
|
||||
this( (ColumnValueParameter) jdbcParameterBinder, jdbcPosition );
|
||||
}
|
||||
|
||||
public JdbcValueDescriptorImpl(ColumnValueParameter columnValueParameter, int jdbcPosition) {
|
||||
this.columnName = columnValueParameter.getColumnReference().getColumnExpression();
|
||||
this.usage = columnValueParameter.getUsage();
|
||||
this.jdbcMapping = columnValueParameter.getJdbcMapping();
|
||||
this.jdbcPosition = jdbcPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterUsage getUsage() {
|
||||
return usage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcPosition() {
|
||||
return jdbcPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMapping getJdbcMapping() {
|
||||
return jdbcMapping;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
|
||||
import org.hibernate.engine.jdbc.spi.MutationStatementPreparer;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.jdbc.TooManyRowsAffectedException;
|
||||
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||
import org.hibernate.sql.model.MutationTarget;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import static org.hibernate.engine.jdbc.mutation.internal.PreparedStatementGroupNone.GROUP_OF_NONE;
|
||||
|
||||
/**
|
||||
* Helper functionality related to model mutations
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ModelMutationHelper {
|
||||
|
||||
private ModelMutationHelper() {
|
||||
// disallow direct instantiation
|
||||
}
|
||||
|
||||
public static void checkResults(
|
||||
OperationResultChecker resultChecker,
|
||||
PreparedStatementDetails statementDetails,
|
||||
int affectedRowCount,
|
||||
int batchPosition) throws SQLException {
|
||||
if ( resultChecker != null ) {
|
||||
resultChecker.checkResult( statementDetails, affectedRowCount, batchPosition );
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean identifiedResultsCheck(
|
||||
PreparedStatementDetails statementDetails,
|
||||
int affectedRowCount,
|
||||
int batchPosition,
|
||||
MutationTarget<?> mutationTarget,
|
||||
Object id,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
try {
|
||||
statementDetails.getExpectation().verifyOutcome(
|
||||
affectedRowCount,
|
||||
statementDetails.getStatement(),
|
||||
batchPosition,
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
}
|
||||
catch (StaleStateException e) {
|
||||
if ( !statementDetails.getMutatingTableDetails().isOptional() && affectedRowCount == 0 ) {
|
||||
final StatisticsImplementor statistics = sessionFactory.getStatistics();
|
||||
if ( statistics.isStatisticsEnabled() ) {
|
||||
statistics.optimisticFailure( mutationTarget.getNavigableRole().getFullPath() );
|
||||
}
|
||||
throw new StaleObjectStateException( mutationTarget.getNavigableRole().getFullPath(), id );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (TooManyRowsAffectedException e) {
|
||||
throw new HibernateException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Duplicate identifier in table (%s) - %s#%s",
|
||||
statementDetails.getMutatingTableDetails().getTableName(),
|
||||
mutationTarget.getNavigableRole().getFullPath(),
|
||||
id
|
||||
)
|
||||
);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static PreparedStatementGroup toPreparedStatementGroup(
|
||||
MutationType mutationType,
|
||||
MutationTarget<?> mutationTarget,
|
||||
List<PreparableMutationOperation> mutations,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( mutations == null || mutations.isEmpty() ) {
|
||||
return GROUP_OF_NONE;
|
||||
}
|
||||
|
||||
if ( mutations.size() == 1 ) {
|
||||
return new PreparedStatementGroupSingleTable( mutations.get( 0 ), session );
|
||||
}
|
||||
|
||||
return new PreparedStatementGroupStandard( mutationType, mutationTarget, mutations, session );
|
||||
}
|
||||
|
||||
public static PreparedStatementDetails standardPreparation(
|
||||
PreparableMutationOperation jdbcMutation,
|
||||
SharedSessionContractImplementor session) {
|
||||
return new PreparedStatementDetailsStandard(
|
||||
jdbcMutation,
|
||||
() -> standardStatementPreparation( jdbcMutation, session ),
|
||||
session.getJdbcServices()
|
||||
);
|
||||
}
|
||||
|
||||
public static PreparedStatementDetails identityPreparation(
|
||||
PreparableMutationOperation jdbcMutation,
|
||||
SharedSessionContractImplementor session) {
|
||||
return new PreparedStatementDetailsStandard(
|
||||
jdbcMutation,
|
||||
() -> {
|
||||
final EntityMutationTarget target = (EntityMutationTarget) jdbcMutation.getMutationTarget();
|
||||
final PreparedStatement statement = target
|
||||
.getIdentityInsertDelegate()
|
||||
.prepareStatement( jdbcMutation.getSqlString(), session );
|
||||
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().register( null, statement );
|
||||
return statement;
|
||||
},
|
||||
session.getJdbcServices()
|
||||
);
|
||||
}
|
||||
|
||||
public static PreparedStatement standardStatementPreparation(
|
||||
PreparableMutationOperation jdbcMutation,
|
||||
SharedSessionContractImplementor session) {
|
||||
final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
|
||||
final MutationStatementPreparer statementPreparer = jdbcCoordinator.getMutationStatementPreparer();
|
||||
final PreparedStatement statement = statementPreparer.prepareStatement( jdbcMutation.getSqlString(), jdbcMutation.isCallable() );
|
||||
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().register( null, statement );
|
||||
return statement;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
|
||||
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||
import org.hibernate.persister.entity.mutation.EntityTableMapping;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||
import org.hibernate.sql.model.SelfExecutingUpdateOperation;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
import org.hibernate.sql.model.jdbc.JdbcValueDescriptor;
|
||||
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER_TRACE_ENABLED;
|
||||
|
||||
/**
|
||||
* Specialized executor for the case of more than one table operation, with the
|
||||
* root table defining a post-insert id-generation strategy.
|
||||
*
|
||||
* @todo (mutation) : look to consolidate this into/with MutationExecutorStandard
|
||||
* - aside from the special handling for the IDENTITY table insert,
|
||||
* the code below is the same as MutationExecutorStandard.
|
||||
* - consolidating this into MutationExecutorStandard would simplify
|
||||
* creating "single table" variations - i.e. MutationExecutorStandard and
|
||||
* StandardSingleTableExecutor. Otherwise we'd have MutationExecutorStandard,
|
||||
* StandardSingleTableExecutor, MutationExecutorPostInsert and
|
||||
* MutationExecutorPostInsertSingleTable variants
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationExecutorPostInsert implements MutationExecutor {
|
||||
private final EntityMutationTarget mutationTarget;
|
||||
private final MutationOperationGroup mutationOperationGroup;
|
||||
|
||||
private final PreparedStatementDetails identityInsertStatementDetails;
|
||||
|
||||
/**
|
||||
* The batched statements
|
||||
*/
|
||||
private final Batch batch;
|
||||
|
||||
/**
|
||||
* Any non-batched JDBC statements
|
||||
*/
|
||||
private final PreparedStatementGroup nonBatchedStatementGroup;
|
||||
|
||||
private final JdbcValueBindingsImpl valueBindings;
|
||||
|
||||
private enum StatementLocation { IDENTITY, BATCHED, NON_BATCHED }
|
||||
private final Map<String, StatementLocation> statementLocationMap = new HashMap<>();
|
||||
|
||||
public MutationExecutorPostInsert(
|
||||
MutationOperationGroup mutationOperationGroup,
|
||||
Supplier<BatchKey> batchKeySupplier,
|
||||
int batchSize,
|
||||
SharedSessionContractImplementor session) {
|
||||
this.mutationTarget = (EntityMutationTarget) mutationOperationGroup.getMutationTarget();
|
||||
this.valueBindings = new JdbcValueBindingsImpl(
|
||||
MutationType.INSERT,
|
||||
mutationTarget,
|
||||
this::findJdbcValueDescriptor
|
||||
);
|
||||
this.mutationOperationGroup = mutationOperationGroup;
|
||||
|
||||
final PreparableMutationOperation identityInsertOperation = mutationOperationGroup.getOperation( mutationTarget.getIdentifierTableName() );
|
||||
this.identityInsertStatementDetails = ModelMutationHelper.identityPreparation(
|
||||
identityInsertOperation,
|
||||
session
|
||||
);
|
||||
statementLocationMap.put( mutationTarget.getIdentifierTableName(), StatementLocation.IDENTITY );
|
||||
|
||||
final BatchKey batchKey = batchKeySupplier.get();
|
||||
|
||||
List<PreparableMutationOperation> batchedJdbcMutations = null;
|
||||
List<PreparableMutationOperation> nonBatchedJdbcMutations = null;
|
||||
|
||||
final List<MutationOperation> operations = mutationOperationGroup.getOperations();
|
||||
for ( int i = 0; i < operations.size(); i++ ) {
|
||||
final MutationOperation operation = operations.get( i );
|
||||
|
||||
if ( operation.getTableDetails().isIdentifierTable() ) {
|
||||
// the identifier table is handled via `identityInsertStatementDetails`
|
||||
continue;
|
||||
}
|
||||
|
||||
// SelfExecutingUpdateOperation are not legal for inserts...
|
||||
assert ! (operation instanceof SelfExecutingUpdateOperation );
|
||||
|
||||
final PreparableMutationOperation preparableMutationOperation = (PreparableMutationOperation) operation;
|
||||
if ( preparableMutationOperation.canBeBatched( batchKey, batchSize ) ) {
|
||||
if ( batchedJdbcMutations == null ) {
|
||||
batchedJdbcMutations = new ArrayList<>();
|
||||
}
|
||||
batchedJdbcMutations.add( preparableMutationOperation );
|
||||
statementLocationMap.put( operation.getTableDetails().getTableName(), StatementLocation.BATCHED );
|
||||
}
|
||||
else {
|
||||
if ( nonBatchedJdbcMutations == null ) {
|
||||
nonBatchedJdbcMutations = new ArrayList<>();
|
||||
}
|
||||
nonBatchedJdbcMutations.add( preparableMutationOperation );
|
||||
statementLocationMap.put( operation.getTableDetails().getTableName(), StatementLocation.NON_BATCHED );
|
||||
}
|
||||
}
|
||||
|
||||
// todo (mutation) : consider creating single PreparedStatementGroup for all
|
||||
// batched and non-batched statements. we then need a way to know whether a
|
||||
// statement is batched or not. `PreparedStatementDetails#isBatched`?
|
||||
|
||||
if ( batchedJdbcMutations == null || batchedJdbcMutations.isEmpty() ) {
|
||||
this.batch = null;
|
||||
}
|
||||
else {
|
||||
final List<PreparableMutationOperation> batchedMutationsRef = batchedJdbcMutations;
|
||||
this.batch = session.getJdbcCoordinator().getBatch2(
|
||||
batchKey,
|
||||
batchSize,
|
||||
() -> ModelMutationHelper.toPreparedStatementGroup(
|
||||
MutationType.INSERT,
|
||||
mutationTarget,
|
||||
batchedMutationsRef,
|
||||
session
|
||||
)
|
||||
);
|
||||
assert batch != null;
|
||||
}
|
||||
|
||||
this.nonBatchedStatementGroup = ModelMutationHelper.toPreparedStatementGroup(
|
||||
MutationType.INSERT,
|
||||
mutationTarget,
|
||||
nonBatchedJdbcMutations,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcValueBindings getJdbcValueBindings() {
|
||||
return valueBindings;
|
||||
}
|
||||
|
||||
private JdbcValueDescriptor findJdbcValueDescriptor(String tableName, String columnName, ParameterUsage usage) {
|
||||
final MutationOperation operation = mutationOperationGroup.getOperation( tableName );
|
||||
if ( operation == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return operation.getJdbcValueDescriptor( columnName, usage );
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementDetails getPreparedStatementDetails(String tableName) {
|
||||
final StatementLocation statementLocation = statementLocationMap.get( tableName );
|
||||
if ( statementLocation == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( statementLocation == StatementLocation.IDENTITY ) {
|
||||
assert mutationTarget.getIdentifierTableName().equals( tableName );
|
||||
return identityInsertStatementDetails;
|
||||
}
|
||||
|
||||
if ( statementLocation == StatementLocation.BATCHED ) {
|
||||
assert batch != null;
|
||||
return batch.getStatementGroup().getPreparedStatementDetails( tableName );
|
||||
}
|
||||
|
||||
if ( statementLocation == StatementLocation.NON_BATCHED ) {
|
||||
assert nonBatchedStatementGroup != null;
|
||||
return nonBatchedStatementGroup.getPreparedStatementDetails( tableName );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(
|
||||
Object modelReference,
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
final InsertGeneratedIdentifierDelegate identityHandler = mutationTarget.getIdentityInsertDelegate();
|
||||
final Object id = identityHandler.performInsert( identityInsertStatementDetails, valueBindings, modelReference, session );
|
||||
|
||||
if ( MODEL_MUTATION_LOGGER_TRACE_ENABLED ) {
|
||||
MODEL_MUTATION_LOGGER.tracef(
|
||||
"Post-insert generated value : `%s` (%s)",
|
||||
id,
|
||||
mutationTarget.getNavigableRole().getFullPath()
|
||||
);
|
||||
}
|
||||
|
||||
if ( nonBatchedStatementGroup != null ) {
|
||||
nonBatchedStatementGroup.forEachStatement( (tableName, statementDetails) -> executeWithId(
|
||||
id,
|
||||
tableName,
|
||||
statementDetails,
|
||||
inclusionChecker,
|
||||
resultChecker,
|
||||
session
|
||||
) );
|
||||
}
|
||||
|
||||
if ( batch != null ) {
|
||||
batch.getStatementGroup().forEachStatement( (tableName, statementDetails) -> executeWithId(
|
||||
id,
|
||||
tableName,
|
||||
statementDetails,
|
||||
inclusionChecker,
|
||||
resultChecker,
|
||||
session
|
||||
) );
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private void executeWithId(
|
||||
Object id,
|
||||
String tableName,
|
||||
PreparedStatementDetails statementDetails,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( statementDetails == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) statementDetails.getMutatingTableDetails();
|
||||
assert !tableDetails.isIdentifierTable();
|
||||
|
||||
if ( inclusionChecker != null && !inclusionChecker.include( tableDetails ) ) {
|
||||
if ( MODEL_MUTATION_LOGGER_TRACE_ENABLED ) {
|
||||
MODEL_MUTATION_LOGGER.tracef(
|
||||
"Skipping execution of secondary insert : %s",
|
||||
tableDetails.getTableName()
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If we get here the statement is needed - make sure it is resolved
|
||||
//noinspection resource
|
||||
statementDetails.resolveStatement();
|
||||
|
||||
tableDetails.getKeyMapping().breakDownKeyJdbcValues(
|
||||
id,
|
||||
(jdbcValue, columnMapping) -> valueBindings.bindValue(
|
||||
jdbcValue,
|
||||
tableName,
|
||||
columnMapping.getColumnName(),
|
||||
ParameterUsage.SET,
|
||||
session
|
||||
),
|
||||
session
|
||||
);
|
||||
|
||||
session.getJdbcServices().getSqlStatementLogger().logStatement( statementDetails.getSqlString() );
|
||||
valueBindings.beforeStatement( statementDetails, session );
|
||||
|
||||
try {
|
||||
final int affectedRowCount = session.getJdbcCoordinator()
|
||||
.getResultSetReturn()
|
||||
.executeUpdate( statementDetails.getStatement() );
|
||||
|
||||
ModelMutationHelper.checkResults( resultChecker, statementDetails, affectedRowCount, -1 );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw session.getJdbcServices().getSqlExceptionHelper().convert(
|
||||
e,
|
||||
"Unable to execute mutation PreparedStatement against table `" + tableName + "`",
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
nonBatchedStatementGroup.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
Locale.ROOT,
|
||||
"MutationExecutorPostInsert(`%s`)",
|
||||
mutationTarget.getNavigableRole().getFullPath()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
|
||||
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
|
||||
import static org.hibernate.engine.jdbc.mutation.internal.ModelMutationHelper.identityPreparation;
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER_TRACE_ENABLED;
|
||||
|
||||
/**
|
||||
* Specialized form of {@link MutationExecutorPostInsert} for cases where there
|
||||
* is only the single identity table. Allows us to skip references to things
|
||||
* we won't need (Batch, etc)
|
||||
*
|
||||
* @todo (mutation) : look to consolidate this into/with MutationExecutorStandard
|
||||
* - aside from the special handling for the IDENTITY table insert,
|
||||
* the code below is the same as MutationExecutorStandard.
|
||||
* - consolidating this into MutationExecutorStandard would simplify
|
||||
* creating "single table" variations - i.e. MutationExecutorStandard and
|
||||
* StandardSingleTableExecutor. Otherwise we'd have MutationExecutorStandard,
|
||||
* StandardSingleTableExecutor, MutationExecutorPostInsert and
|
||||
* MutationExecutorPostInsertSingleTable variants
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationExecutorPostInsertSingleTable implements MutationExecutor {
|
||||
private final EntityMutationTarget mutationTarget;
|
||||
private final SharedSessionContractImplementor session;
|
||||
|
||||
private final PreparedStatementDetails identityInsertStatementDetails;
|
||||
|
||||
private final JdbcValueBindingsImpl valueBindings;
|
||||
|
||||
public MutationExecutorPostInsertSingleTable(
|
||||
MutationOperationGroup mutationOperationGroup,
|
||||
SharedSessionContractImplementor session) {
|
||||
this.mutationTarget = (EntityMutationTarget) mutationOperationGroup.getMutationTarget();
|
||||
this.session = session;
|
||||
|
||||
assert mutationOperationGroup.getNumberOfOperations() == 1;
|
||||
|
||||
final PreparableMutationOperation operation = mutationOperationGroup.getOperation( mutationTarget.getIdentifierTableName() );
|
||||
this.identityInsertStatementDetails = identityPreparation( operation, session );
|
||||
|
||||
this.valueBindings = new JdbcValueBindingsImpl(
|
||||
MutationType.INSERT,
|
||||
mutationTarget,
|
||||
(tableName, columnName, usage) -> {
|
||||
assert identityInsertStatementDetails.getMutatingTableDetails().getTableName().equals( tableName );
|
||||
return operation.findValueDescriptor( columnName, usage );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcValueBindings getJdbcValueBindings() {
|
||||
return valueBindings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementDetails getPreparedStatementDetails(String tableName) {
|
||||
if ( mutationTarget.getIdentifierTableName().equals( tableName ) ) {
|
||||
return identityInsertStatementDetails;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(
|
||||
Object modelReference,
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
final InsertGeneratedIdentifierDelegate identityHandler = mutationTarget.getIdentityInsertDelegate();
|
||||
final Object id = identityHandler.performInsert( identityInsertStatementDetails, valueBindings, modelReference, session );
|
||||
|
||||
if ( MODEL_MUTATION_LOGGER_TRACE_ENABLED ) {
|
||||
MODEL_MUTATION_LOGGER.tracef(
|
||||
"Post-insert generated value : `%s` (%s)",
|
||||
id,
|
||||
mutationTarget.getNavigableRole().getFullPath()
|
||||
);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
identityInsertStatementDetails.releaseStatement( session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
Locale.ROOT,
|
||||
"MutationExecutorPostInsertSingleTable(`%s`)",
|
||||
mutationTarget.getNavigableRole().getFullPath()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
/**
|
||||
* Initiator for the {@link MutationExecutorService} service
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationExecutorServiceInitiator implements StandardServiceInitiator<MutationExecutorService> {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final MutationExecutorServiceInitiator INSTANCE = new MutationExecutorServiceInitiator();
|
||||
|
||||
/**
|
||||
* Names the BatchBuilder implementation to use.
|
||||
*/
|
||||
public static final String EXECUTOR_KEY = "hibernate.jdbc.mutation.executor";
|
||||
|
||||
@Override
|
||||
public Class<MutationExecutorService> getServiceInitiated() {
|
||||
return MutationExecutorService.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutationExecutorService initiateService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
||||
final Object custom = configurationValues.get( EXECUTOR_KEY );
|
||||
|
||||
if ( custom == null ) {
|
||||
return createStandardService( configurationValues, registry );
|
||||
}
|
||||
|
||||
if ( custom instanceof MutationExecutorService ) {
|
||||
return (MutationExecutorService) custom;
|
||||
}
|
||||
|
||||
final Class<? extends MutationExecutorService> customImplClass;
|
||||
if ( custom instanceof Class ) {
|
||||
//noinspection unchecked
|
||||
customImplClass = (Class<? extends MutationExecutorService>) custom;
|
||||
}
|
||||
else {
|
||||
final ClassLoaderService classLoaderService = registry.getService( ClassLoaderService.class );
|
||||
customImplClass = classLoaderService.classForName( custom.toString() );
|
||||
}
|
||||
|
||||
try {
|
||||
return customImplClass.getConstructor().newInstance();
|
||||
}
|
||||
catch (NoSuchMethodException e) {
|
||||
throw new HibernateException( "Could not locate appropriate MutationExecutorService constructor : " + customImplClass.getName(), e );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new HibernateException( "Unable to instantiate custom MutationExecutorService : " + customImplClass.getName(), e );
|
||||
}
|
||||
}
|
||||
|
||||
private MutationExecutorService createStandardService(Map<String, Object> configurationValues, ServiceRegistryImplementor registry) {
|
||||
return new StandardMutationExecutorService( configurationValues, registry );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationExecutorSingleBatched extends AbstractSingleMutationExecutor {
|
||||
private final int batchSize;
|
||||
private final SharedSessionContractImplementor session;
|
||||
|
||||
private final BatchKey batchKey;
|
||||
|
||||
public MutationExecutorSingleBatched(
|
||||
PreparableMutationOperation mutationOperation,
|
||||
BatchKey batchKey,
|
||||
int batchSize,
|
||||
SharedSessionContractImplementor session) {
|
||||
super( mutationOperation );
|
||||
|
||||
this.batchSize = batchSize;
|
||||
this.session = session;
|
||||
|
||||
this.batchKey = batchKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreparedStatementGroupSingleTable getStatementGroup() {
|
||||
return (PreparedStatementGroupSingleTable) resolveBatch().getStatementGroup();
|
||||
}
|
||||
|
||||
private Batch batch;
|
||||
|
||||
private Batch resolveBatch() {
|
||||
if ( batch == null ) {
|
||||
batch = session.getJdbcCoordinator().getBatch2(
|
||||
batchKey,
|
||||
batchSize,
|
||||
() -> new PreparedStatementGroupSingleTable( getMutationOperation(), session )
|
||||
);
|
||||
assert batch != null;
|
||||
}
|
||||
|
||||
return batch;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performBatchedOperations(ValuesAnalysis valuesAnalysis, TableInclusionChecker inclusionChecker) {
|
||||
resolveBatch().addToBatch( getJdbcValueBindings(), inclusionChecker );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationExecutorSingleNonBatched extends AbstractSingleMutationExecutor {
|
||||
private final PreparedStatementGroupSingleTable statementGroup;
|
||||
|
||||
public MutationExecutorSingleNonBatched(
|
||||
PreparableMutationOperation mutationOperation,
|
||||
SharedSessionContractImplementor session) {
|
||||
super( mutationOperation );
|
||||
|
||||
this.statementGroup = new PreparedStatementGroupSingleTable( mutationOperation, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreparedStatementGroupSingleTable getStatementGroup() {
|
||||
return statementGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performNonBatchedOperations(
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
performNonBatchedMutation(
|
||||
statementGroup.getSingleStatementDetails(),
|
||||
getJdbcValueBindings(),
|
||||
inclusionChecker,
|
||||
resultChecker,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
// nothing to do - `#performNonBatchedMutation` already releases the statement
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.model.SelfExecutingUpdateOperation;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
import org.hibernate.sql.model.jdbc.JdbcValueDescriptor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationExecutorSingleSelfExecuting extends AbstractMutationExecutor {
|
||||
private final SelfExecutingUpdateOperation operation;
|
||||
private final JdbcValueBindingsImpl valueBindings;
|
||||
|
||||
public MutationExecutorSingleSelfExecuting(SelfExecutingUpdateOperation operation) {
|
||||
this.operation = operation;
|
||||
|
||||
this.valueBindings = new JdbcValueBindingsImpl(
|
||||
operation.getMutationType(),
|
||||
operation.getMutationTarget(),
|
||||
this::findJdbcValueDescriptor
|
||||
);
|
||||
}
|
||||
|
||||
private JdbcValueDescriptor findJdbcValueDescriptor(String tableName, String columnName, ParameterUsage usage) {
|
||||
return operation.findValueDescriptor( columnName, usage );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcValueBindings getJdbcValueBindings() {
|
||||
return valueBindings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementDetails getPreparedStatementDetails(String tableName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performSelfExecutingOperations(ValuesAnalysis valuesAnalysis, TableInclusionChecker inclusionChecker, SharedSessionContractImplementor session) {
|
||||
if ( inclusionChecker.include( operation.getTableDetails() ) ) {
|
||||
operation.performMutation( valueBindings, valuesAnalysis, session );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
// todo (mutation) :implement
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.engine.jdbc.batch.spi.Batch;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||
import org.hibernate.sql.model.SelfExecutingUpdateOperation;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
import org.hibernate.sql.model.jdbc.JdbcValueDescriptor;
|
||||
|
||||
/**
|
||||
* Standard MutationExecutor implementation
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationExecutorStandard extends AbstractMutationExecutor {
|
||||
private final MutationOperationGroup mutationOperationGroup;
|
||||
|
||||
/**
|
||||
* The batched statements
|
||||
*/
|
||||
private final Batch batch;
|
||||
|
||||
/**
|
||||
* Any non-batched JDBC statements
|
||||
*/
|
||||
private final PreparedStatementGroup nonBatchedStatementGroup;
|
||||
|
||||
/**
|
||||
* Operations which handle their own execution
|
||||
*/
|
||||
private final List<SelfExecutingUpdateOperation> selfExecutingMutations;
|
||||
|
||||
private final JdbcValueBindingsImpl valueBindings;
|
||||
|
||||
private enum StatementLocation { BATCHED, NON_BATCHED }
|
||||
private final Map<String,StatementLocation> statementLocationMap = new HashMap<>();
|
||||
|
||||
public MutationExecutorStandard(
|
||||
MutationOperationGroup mutationOperationGroup,
|
||||
Supplier<BatchKey> batchKeySupplier,
|
||||
int batchSize,
|
||||
SharedSessionContractImplementor session) {
|
||||
this.mutationOperationGroup = mutationOperationGroup;
|
||||
|
||||
final BatchKey batchKey = batchKeySupplier.get();
|
||||
|
||||
// split the table operations into batchable and non-batchable -
|
||||
// 1. batchable statements are handle via Batch
|
||||
// 2. non-batchable statements are handled locally
|
||||
|
||||
List<PreparableMutationOperation> batchedJdbcMutations = null;
|
||||
List<PreparableMutationOperation> nonBatchedJdbcMutations = null;
|
||||
List<SelfExecutingUpdateOperation> selfExecutingMutations = null;
|
||||
|
||||
final List<MutationOperation> operations = mutationOperationGroup.getOperations();
|
||||
|
||||
boolean hasAnyNonBatchedJdbcOperations = false;
|
||||
|
||||
for ( int i = operations.size() - 1; i >= 0; i-- ) {
|
||||
final MutationOperation operation = operations.get( i );
|
||||
if ( operation instanceof SelfExecutingUpdateOperation ) {
|
||||
final SelfExecutingUpdateOperation selfExecutingMutation = (SelfExecutingUpdateOperation) operation;
|
||||
if ( selfExecutingMutations == null ) {
|
||||
selfExecutingMutations = new ArrayList<>();
|
||||
}
|
||||
selfExecutingMutations.add( 0, selfExecutingMutation );
|
||||
}
|
||||
else {
|
||||
final PreparableMutationOperation preparableMutationOperation = (PreparableMutationOperation) operation;
|
||||
final TableMapping tableDetails = operation.getTableDetails();
|
||||
final boolean canBeBatched;
|
||||
|
||||
if ( tableDetails.isIdentifierTable() && hasAnyNonBatchedJdbcOperations ) {
|
||||
canBeBatched = false;
|
||||
}
|
||||
else {
|
||||
canBeBatched = preparableMutationOperation.canBeBatched( batchKey, batchSize );
|
||||
}
|
||||
|
||||
if ( canBeBatched ) {
|
||||
if ( batchedJdbcMutations == null ) {
|
||||
batchedJdbcMutations = new ArrayList<>();
|
||||
}
|
||||
batchedJdbcMutations.add( 0, preparableMutationOperation );
|
||||
statementLocationMap.put( tableDetails.getTableName(), StatementLocation.BATCHED );
|
||||
}
|
||||
else {
|
||||
hasAnyNonBatchedJdbcOperations = true;
|
||||
if ( nonBatchedJdbcMutations == null ) {
|
||||
nonBatchedJdbcMutations = new ArrayList<>();
|
||||
}
|
||||
nonBatchedJdbcMutations.add( 0, preparableMutationOperation );
|
||||
statementLocationMap.put( tableDetails.getTableName(), StatementLocation.NON_BATCHED );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo (mutation) : consider creating single PreparedStatementGroup for all
|
||||
// batched and non-batched statements. we then need a way to know whether a
|
||||
// statement is batched or not. `PreparedStatementDetails#isBatched`?
|
||||
|
||||
if ( batchedJdbcMutations == null || batchedJdbcMutations.isEmpty() ) {
|
||||
this.batch = null;
|
||||
}
|
||||
else {
|
||||
final List<PreparableMutationOperation> batchedMutationsRef = batchedJdbcMutations;
|
||||
this.batch = session.getJdbcCoordinator().getBatch2(
|
||||
batchKey,
|
||||
batchSize,
|
||||
() -> ModelMutationHelper.toPreparedStatementGroup(
|
||||
mutationOperationGroup.getMutationType(),
|
||||
mutationOperationGroup.getMutationTarget(),
|
||||
batchedMutationsRef,
|
||||
session
|
||||
)
|
||||
);
|
||||
assert batch != null;
|
||||
}
|
||||
|
||||
this.nonBatchedStatementGroup = ModelMutationHelper.toPreparedStatementGroup(
|
||||
mutationOperationGroup.getMutationType(),
|
||||
mutationOperationGroup.getMutationTarget(),
|
||||
nonBatchedJdbcMutations,
|
||||
session
|
||||
);
|
||||
|
||||
this.selfExecutingMutations = selfExecutingMutations;
|
||||
|
||||
this.valueBindings = new JdbcValueBindingsImpl(
|
||||
mutationOperationGroup.getMutationType(),
|
||||
mutationOperationGroup.getMutationTarget(),
|
||||
this::findJdbcValueDescriptor
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcValueBindings getJdbcValueBindings() {
|
||||
return valueBindings;
|
||||
}
|
||||
|
||||
private JdbcValueDescriptor findJdbcValueDescriptor(String tableName, String columnName, ParameterUsage usage) {
|
||||
return mutationOperationGroup.getOperation( tableName ).findValueDescriptor( columnName, usage );
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatementDetails getPreparedStatementDetails(String tableName) {
|
||||
final StatementLocation statementLocation = statementLocationMap.get( tableName );
|
||||
if ( statementLocation == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( statementLocation == StatementLocation.BATCHED ) {
|
||||
assert batch != null;
|
||||
return batch.getStatementGroup().getPreparedStatementDetails( tableName );
|
||||
}
|
||||
|
||||
if ( statementLocation == StatementLocation.NON_BATCHED ) {
|
||||
assert nonBatchedStatementGroup != null;
|
||||
return nonBatchedStatementGroup.getPreparedStatementDetails( tableName );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
nonBatchedStatementGroup.release();
|
||||
// todo (mutation) :implement
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performNonBatchedOperations(
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker,
|
||||
OperationResultChecker resultChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
if ( nonBatchedStatementGroup == null || nonBatchedStatementGroup.getNumberOfStatements() <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
nonBatchedStatementGroup.forEachStatement( (tableName, statementDetails) -> performNonBatchedMutation(
|
||||
statementDetails,
|
||||
valueBindings,
|
||||
inclusionChecker,
|
||||
resultChecker,
|
||||
session
|
||||
) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performSelfExecutingOperations(ValuesAnalysis valuesAnalysis, TableInclusionChecker inclusionChecker, SharedSessionContractImplementor session) {
|
||||
if ( selfExecutingMutations == null || selfExecutingMutations.isEmpty() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < selfExecutingMutations.size(); i++ ) {
|
||||
final SelfExecutingUpdateOperation operation = selfExecutingMutations.get( i );
|
||||
if ( inclusionChecker.include( operation.getTableDetails() ) ) {
|
||||
operation.performMutation( valueBindings, valuesAnalysis, session );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performBatchedOperations(
|
||||
ValuesAnalysis valuesAnalysis,
|
||||
TableInclusionChecker inclusionChecker) {
|
||||
if ( batch == null ) {
|
||||
return;
|
||||
}
|
||||
batch.addToBatch( valueBindings, inclusionChecker );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
Locale.ROOT,
|
||||
"MutationExecutorStandard(`%s:%s`)",
|
||||
mutationOperationGroup.getMutationType().name(),
|
||||
mutationOperationGroup.getMutationTarget().getRolePath()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.graph.spi.AppliedGraph;
|
||||
import org.hibernate.query.ResultListTransformer;
|
||||
import org.hibernate.query.TupleTransformer;
|
||||
import org.hibernate.query.spi.Limit;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
|
||||
import jakarta.persistence.CacheRetrieveMode;
|
||||
import jakarta.persistence.CacheStoreMode;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MutationQueryOptions implements QueryOptions {
|
||||
public static final MutationQueryOptions INSTANCE = new MutationQueryOptions();
|
||||
|
||||
@Override
|
||||
public Integer getTimeout() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlushMode getFlushMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isReadOnly() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppliedGraph getAppliedGraph() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TupleTransformer<?> getTupleTransformer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultListTransformer<?> getResultListTransformer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean isResultCachingEnabled() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheRetrieveMode getCacheRetrieveMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheStoreMode getCacheStoreMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultCacheRegionName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockOptions getLockOptions() {
|
||||
return LockOptions.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDatabaseHints() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getFetchSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Limit getLimit() {
|
||||
return LimitImpl.INSTANCE;
|
||||
}
|
||||
|
||||
private static class LimitImpl extends Limit {
|
||||
public static final LimitImpl INSTANCE = new LimitImpl();
|
||||
|
||||
@Override
|
||||
public void setFirstRow(Integer firstRow) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(int maxRows) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(Integer maxRows) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Limit makeCopy() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.engine.jdbc.mutation.internal;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementGroup;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.sql.model.PreparableMutationOperation;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
|
||||
/**
|
||||
* Describes a particular PreparedStatement within a {@linkplain PreparedStatementGroup group}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PreparedStatementDetailsStandard implements PreparedStatementDetails {
|
||||
private final TableMapping mutatingTableDetails;
|
||||
private final String sql;
|
||||
private final Supplier<PreparedStatement> jdbcStatementCreator;
|
||||
private final Expectation expectation;
|
||||
private final JdbcServices jdbcServices;
|
||||
|
||||
private PreparedStatement statement;
|
||||
|
||||
public PreparedStatementDetailsStandard(
|
||||
PreparableMutationOperation tableMutation,
|
||||
Supplier<PreparedStatement> jdbcStatementCreator,
|
||||
JdbcServices jdbcServices) {
|
||||
this(
|
||||
tableMutation,
|
||||
tableMutation.getSqlString(),
|
||||
jdbcStatementCreator,
|
||||
tableMutation.getExpectation(),
|
||||
jdbcServices
|
||||
);
|
||||
}
|
||||
|
||||
public PreparedStatementDetailsStandard(
|
||||
PreparableMutationOperation tableMutation,
|
||||
String sql,
|
||||
Supplier<PreparedStatement> jdbcStatementCreator,
|
||||
Expectation expectation,
|
||||
JdbcServices jdbcServices) {
|
||||
|
||||
// todo (mutation) : have `parameterDescriptors` be passed in.
|
||||
// - these descriptors being only available relative solely
|
||||
// to a preparable operation, rather than more widely scoped to
|
||||
// the `MutationOperation`, causes problems for self-executing operations
|
||||
|
||||
this.mutatingTableDetails = tableMutation.getTableDetails();
|
||||
this.sql = sql;
|
||||
this.jdbcStatementCreator = jdbcStatementCreator;
|
||||
this.expectation = expectation;
|
||||
this.jdbcServices = jdbcServices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableMapping getMutatingTableDetails() {
|
||||
return mutatingTableDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseStatement(SharedSessionContractImplementor session) {
|
||||
if ( statement != null ) {
|
||||
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( statement );
|
||||
statement = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlString() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement getStatement() {
|
||||
return statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreparedStatement resolveStatement() {
|
||||
if ( statement == null ) {
|
||||
statement = jdbcStatementCreator.get();
|
||||
try {
|
||||
expectation.prepare( statement );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw jdbcServices.getSqlExceptionHelper().convert(
|
||||
e,
|
||||
"Unable to prepare for expectation",
|
||||
sql
|
||||
);
|
||||
}
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expectation getExpectation() {
|
||||
return expectation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PreparedStatementDetails(" + sql + ")";
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue