HHH-15393 - Improve write-paths to use mapping model

HHH-15723 - Fix foreign-key modeling
This commit is contained in:
Steve Ebersole 2022-11-25 12:03:56 -06:00
parent 4cce83a779
commit a9ac98b364
436 changed files with 22797 additions and 7244 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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();
}

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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 );
}
};

View File

@ -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;

View File

@ -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()

View File

@ -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;

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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()
)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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})

View File

@ -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() ) {

View File

@ -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 );
}
}

View File

@ -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")

View File

@ -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;

View File

@ -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";

View File

@ -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?
*

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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
}

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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()

View File

@ -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 );
}
}
}
}

View File

@ -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( ")" );
}
}

View File

@ -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();" );
}
}

View File

@ -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

View File

@ -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

View File

@ -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 );
}
}

View File

@ -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

View File

@ -156,11 +156,15 @@ public final class Versioning {
if ( hasDirtyCollections ) {
return true;
}
if ( dirtyProperties != null ) {
for ( int dirtyProperty : dirtyProperties ) {
if ( propertyVersionability[dirtyProperty] ) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,46 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.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);
}

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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 + ")";
}
}

View File

@ -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
);
}
}

View File

@ -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 );

View File

@ -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() + ")";
}
}

View File

@ -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 );
}
}
}

View File

@ -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
}
}

View File

@ -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 );
}
}

View File

@ -1,33 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.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 );
}
}

View File

@ -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." );
}
}
}

View File

@ -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.

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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,18 +182,24 @@ 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 ) {
try {
currentBatch.execute();
// needed?
}
finally {
currentBatch.release();
}
}
}
@Override
public void abortBatch() {
@ -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

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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() )
);
}
}

View File

@ -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 );
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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()
);
}
}

View File

@ -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()
);
}
}

View File

@ -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 );
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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()
);
}
}

View File

@ -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;
}
}
}

View File

@ -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