HHH-15191 - Remove support for Derby versions older than 10.14.2.0

Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
Jan Schatteman 2022-06-23 18:45:58 +02:00 committed by Christian Beikov
parent 96f56db700
commit 4d4aaf3b4a
10 changed files with 1384 additions and 58 deletions

View File

@ -0,0 +1,957 @@
/*
* 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.community.dialect;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.dialect.RowLockStrategy;
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
import org.hibernate.dialect.function.CastingConcatFunction;
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.InsertSubstringOverlayEmulation;
import org.hibernate.dialect.identity.DB2IdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
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.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
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.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.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.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
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.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorDerbyDatabaseImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.BigDecimalJavaType;
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.TimestampJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.TemporalType;
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.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.
*
* @author Simon Johnston
* @author Gavin King
*
*/
public class DerbyLegacyDialect extends Dialect {
// KNOWN LIMITATIONS:
// no support for nationalized data (nchar, nvarchar, nclob)
// * limited set of fields for extract()
// (no 'day of xxxx', nor 'week of xxxx')
// * no support for format()
// * pad() can only pad with blanks
// * can't cast String to Binary
// * can't select a parameter unless wrapped
// in a cast or function call
private final LimitHandler limitHandler = getVersion().isBefore( 10, 5 )
? AbstractLimitHandler.NO_LIMIT
: new DerbyLimitHandler( getVersion().isSameOrAfter( 10, 6 ) );
public DerbyLegacyDialect() {
this( DatabaseVersion.make( 10, 0 ) );
}
public DerbyLegacyDialect(DatabaseVersion version) {
super(version);
}
public DerbyLegacyDialect(DialectResolutionInfo info) {
super(info);
}
@Override
protected String columnType(int sqlTypeCode) {
switch ( sqlTypeCode ) {
case BOOLEAN:
return getVersion().isBefore( 10, 7 ) ? "smallint" : super.columnType( sqlTypeCode );
case TINYINT:
//no tinyint
return "smallint";
case NUMERIC:
// HHH-12827: map them both to the same type to avoid problems with schema update
// Note that 31 is the maximum precision Derby supports
return columnType( DECIMAL );
case VARBINARY:
return "varchar($l) for bit data";
case LONG32VARBINARY:
return "long varchar for bit data";
case NCHAR:
return columnType( CHAR );
case NVARCHAR:
return columnType( VARCHAR );
case LONG32VARCHAR:
return "long varchar";
case BLOB:
return "blob";
case CLOB:
case NCLOB:
return "clob";
case TIMESTAMP:
case TIMESTAMP_WITH_TIMEZONE:
return "timestamp";
}
return super.columnType( sqlTypeCode );
}
@Override
protected void registerColumnTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.registerColumnTypes( typeContributions, serviceRegistry );
final DdlTypeRegistry ddlTypeRegistry = typeContributions.getTypeConfiguration().getDdlTypeRegistry();
//long varchar is the right type to use for lengths between 32_672 and 32_700
int maxLongVarcharLength = 32_700;
ddlTypeRegistry.addDescriptor(
CapacityDependentDdlType.builder( VARBINARY, columnType( BLOB ), columnType( VARBINARY ), this )
.withTypeCapacity( getMaxVarbinaryLength(), columnType( VARBINARY ) )
.withTypeCapacity( maxLongVarcharLength, columnType( LONG32VARBINARY ) )
.build()
);
ddlTypeRegistry.addDescriptor(
CapacityDependentDdlType.builder( VARCHAR, columnType( CLOB ), columnType( VARCHAR ), this )
.withTypeCapacity( getMaxVarcharLength(), columnType( VARCHAR ) )
.withTypeCapacity( maxLongVarcharLength, columnType( LONG32VARCHAR ) )
.build()
);
ddlTypeRegistry.addDescriptor(
CapacityDependentDdlType.builder( NVARCHAR, columnType( CLOB ), columnType( NVARCHAR ), this )
.withTypeCapacity( getMaxVarcharLength(), columnType( NVARCHAR ) )
.withTypeCapacity( maxLongVarcharLength, columnType( LONG32VARCHAR ) )
.build()
);
ddlTypeRegistry.addDescriptor(
CapacityDependentDdlType.builder( BINARY, columnType( BLOB ), columnType( VARBINARY ), this )
.withTypeCapacity( 254, "char($l) for bit data" )
.withTypeCapacity( getMaxVarbinaryLength(), columnType( VARBINARY ) )
.withTypeCapacity( maxLongVarcharLength, columnType( LONG32VARBINARY ) )
.build()
);
// This is the maximum size for the CHAR datatype on Derby
ddlTypeRegistry.addDescriptor(
CapacityDependentDdlType.builder( CHAR, columnType( CLOB ), columnType( CHAR ), this )
.withTypeCapacity( 254, columnType( CHAR ) )
.withTypeCapacity( getMaxVarcharLength(), columnType( VARCHAR ) )
.withTypeCapacity( maxLongVarcharLength, columnType( LONG32VARCHAR ) )
.build()
);
ddlTypeRegistry.addDescriptor(
CapacityDependentDdlType.builder( NCHAR, columnType( CLOB ), columnType( NCHAR ), this )
.withTypeCapacity( 254, columnType( NCHAR ) )
.withTypeCapacity( getMaxVarcharLength(), columnType( NVARCHAR ) )
.withTypeCapacity( maxLongVarcharLength, columnType( LONG32NVARCHAR ) )
.build()
);
}
@Override
public int getMaxVarcharLength() {
return 32_672;
}
@Override
public int getDefaultDecimalPrecision() {
//this is the maximum allowed in Derby
return 31;
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return getVersion().isBefore( 10, 7 )
? Types.SMALLINT
: Types.BOOLEAN;
}
@Override
public NationalizationSupport getNationalizationSupport() {
return NationalizationSupport.IMPLICIT;
}
@Override
public int getDefaultStatementBatchSize() {
return 15;
}
@Override
public int getFloatPrecision() {
return 23;
}
@Override
public int getDoublePrecision() {
return 52;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
final BasicTypeRegistry basicTypeRegistry = queryEngine.getTypeConfiguration().getBasicTypeRegistry();
final BasicType<String> stringType = basicTypeRegistry.resolve( StandardBasicTypes.STRING );
CommonFunctionFactory functionFactory = new CommonFunctionFactory(queryEngine);
// Derby needs an actual argument type for aggregates like SUM, AVG, MIN, MAX to determine the result type
functionFactory.aggregates( this, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
queryEngine.getSqmFunctionRegistry().register(
"count",
new CountFunction(
this,
queryEngine.getTypeConfiguration(),
SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER,
"||",
queryEngine.getTypeConfiguration().getDdlTypeRegistry().getDescriptor( VARCHAR )
.getCastTypeName( stringType, null, null, null ),
true
)
);
// AVG by default uses the input type, so we possibly need to cast the argument type, hence a special function
functionFactory.avg_castingNonDoubleArguments( this, SqlAstNodeRenderingMode.DEFAULT );
functionFactory.concat_pipeOperator();
functionFactory.cot();
functionFactory.chr_char();
functionFactory.degrees();
functionFactory.radians();
functionFactory.log10();
functionFactory.sinh();
functionFactory.cosh();
functionFactory.tanh();
functionFactory.pi();
functionFactory.rand();
functionFactory.trim1();
functionFactory.hourMinuteSecond();
functionFactory.yearMonthDay();
functionFactory.varPopSamp();
functionFactory.stddevPopSamp();
functionFactory.substring_substr();
functionFactory.leftRight_substrLength();
functionFactory.characterLength_length( SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
functionFactory.power_expLn();
functionFactory.round_floor();
functionFactory.octetLength_pattern( "length(?1)" );
functionFactory.bitLength_pattern( "length(?1)*8" );
queryEngine.getSqmFunctionRegistry().register(
"concat",
new CastingConcatFunction(
this,
"||",
true,
SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER,
queryEngine.getTypeConfiguration()
)
);
//no way I can see to pad with anything other than spaces
queryEngine.getSqmFunctionRegistry().register( "lpad", new DerbyLpadEmulation( queryEngine.getTypeConfiguration() ) );
queryEngine.getSqmFunctionRegistry().register( "rpad", new DerbyRpadEmulation( queryEngine.getTypeConfiguration() ) );
queryEngine.getSqmFunctionRegistry().register( "least", new CaseLeastGreatestEmulation( true ) );
queryEngine.getSqmFunctionRegistry().register( "greatest", new CaseLeastGreatestEmulation( false ) );
queryEngine.getSqmFunctionRegistry().register( "overlay", new InsertSubstringOverlayEmulation( queryEngine.getTypeConfiguration(), true ) );
}
@Override
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
return new StandardSqlAstTranslatorFactory() {
@Override
protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
SessionFactoryImplementor sessionFactory, Statement statement) {
return new DerbyLegacySqlAstTranslator<>( sessionFactory, statement );
}
};
}
/**
* Derby doesn't have an extract() function, and has
* no functions at all for calendaring, but we can
* emulate the most basic functionality of extract()
* using the functions it does have.
*
* The only supported {@link TemporalUnit}s are:
* {@link TemporalUnit#YEAR},
* {@link TemporalUnit#MONTH}
* {@link TemporalUnit#DAY},
* {@link TemporalUnit#HOUR},
* {@link TemporalUnit#MINUTE},
* {@link TemporalUnit#SECOND} (along with
* {@link TemporalUnit#NANOSECOND},
* {@link TemporalUnit#DATE}, and
* {@link TemporalUnit#TIME}, which are desugared
* by the parser).
*/
@Override
public String extractPattern(TemporalUnit unit) {
switch (unit) {
case DAY_OF_MONTH:
return "day(?2)";
case DAY_OF_YEAR:
return "({fn timestampdiff(sql_tsi_day,date(char(year(?2),4)||'-01-01'),?2)}+1)";
case DAY_OF_WEEK:
// Use the approach as outlined here: https://stackoverflow.com/questions/36357013/day-of-week-from-seconds-since-epoch
return "(mod(mod({fn timestampdiff(sql_tsi_day,{d '1970-01-01'},?2)}+4,7)+7,7)+1)";
case WEEK:
// Use the approach as outlined here: https://www.sqlservercentral.com/articles/a-simple-formula-to-calculate-the-iso-week-number
// In SQL Server terms this is (DATEPART(dy,DATEADD(dd,DATEDIFF(dd,'17530101',@SomeDate)/7*7,'17530104'))+6)/7
return "(({fn timestampdiff(sql_tsi_day,date(char(year(?2),4)||'-01-01'),{fn timestampadd(sql_tsi_day,{fn timestampdiff(sql_tsi_day,{d '1753-01-01'},?2)}/7*7,{d '1753-01-04'})})}+7)/7)";
case QUARTER:
return "((month(?2)+2)/3)";
default:
return "?1(?2)";
}
}
@Override
public String translateExtractField(TemporalUnit unit) {
switch (unit) {
case WEEK:
case DAY_OF_YEAR:
case DAY_OF_WEEK:
throw new UnsupportedOperationException("field type not supported on Derby: " + unit);
case DAY_OF_MONTH:
return "day";
default:
return super.translateExtractField(unit);
}
}
/**
* Derby does have a real {@link Types#BOOLEAN}
* type, but it doesn't know how to cast to it. Worse,
* Derby makes us use the {@code double()} function to
* cast things to its floating point types.
*/
@Override
public String castPattern(CastType from, CastType to) {
switch ( to ) {
case FLOAT:
return "cast(double(?1) as real)";
case DOUBLE:
return "double(?1)";
case STRING:
// Derby madness http://db.apache.org/derby/docs/10.8/ref/rrefsqlj33562.html
// With a nice rant: https://blog.jooq.org/2011/10/29/derby-casting-madness-the-sequel/
// See https://issues.apache.org/jira/browse/DERBY-2072
// Since numerics can't be cast to varchar directly, use char(254) i.e. with the maximum char capacity
// as an intermediate type before converting to varchar
switch ( from ) {
case FLOAT:
case DOUBLE:
// Derby can't cast to char directly, but needs to be cast to decimal first...
return "cast(trim(cast(cast(?1 as decimal(" + getDefaultDecimalPrecision() + "," + BigDecimalJavaType.INSTANCE.getDefaultSqlScale( this, null ) + ")) as char(254))) as ?2)";
case INTEGER:
case LONG:
case FIXED:
return "cast(trim(cast(?1 as char(254))) as ?2)";
case DATE:
// The maximum length of a date
return "cast(?1 as varchar(10))";
case TIME:
// The maximum length of a time
return "cast(?1 as varchar(8))";
case TIMESTAMP:
// The maximum length of a timestamp
return "cast(?1 as varchar(30))";
}
break;
}
return super.castPattern( from, to );
}
@Override
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "{fn timestampadd(sql_tsi_frac_second,mod(bigint(?2),1000000000),{fn timestampadd(sql_tsi_second,bigint((?2)/1000000000),?3)})}";
default:
return "{fn timestampadd(sql_tsi_?1,bigint(?2),?3)}";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "{fn timestampdiff(sql_tsi_frac_second,?2,?3)}";
default:
return "{fn timestampdiff(sql_tsi_?1,?2,?3)}";
}
}
@Override
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
if ( getVersion().isBefore( 10, 7 ) ) {
appender.appendSql( bool ? '1' : '0' );
}
else {
appender.appendSql( bool );
}
}
@Override
public SequenceSupport getSequenceSupport() {
return getVersion().isBefore( 10, 6 )
? super.getSequenceSupport()
: DerbySequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return getVersion().isBefore( 10, 6 )
? null
: "select sys.sysschemas.schemaname as sequence_schema,sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid=sys.sysschemas.schemaid";
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return getVersion().isBefore( 10, 6 )
? SequenceInformationExtractorNoOpImpl.INSTANCE
: SequenceInformationExtractorDerbyDatabaseImpl.INSTANCE;
}
@Override
public String[] getDropSchemaCommand(String schemaName) {
return new String[] {"drop schema " + schemaName + " restrict"};
}
@Override
public String getSelectClauseNullString(int sqlType, TypeConfiguration typeConfiguration) {
return DB2Dialect.selectNullString( sqlType );
}
@Override
public boolean supportsCommentOn() {
//HHH-4531
return false;
}
@Override
public RowLockStrategy getWriteRowLockStrategy() {
return RowLockStrategy.NONE;
}
@Override
public RowLockStrategy getReadRowLockStrategy() {
return RowLockStrategy.NONE;
}
@Override
public String getForUpdateString() {
return " for update with rs";
}
@Override
public String getWriteLockString(int timeout) {
return " for update with rs";
}
@Override
public String getReadLockString(int timeout) {
return " for read only with rs";
}
@Override
public boolean supportsOuterJoinForUpdate() {
//TODO: check this!
return false;
}
@Override
public boolean supportsExistsInSelect() {
//TODO: check this!
return false;
}
@Override
public boolean supportsLockTimeouts() {
// To enable the lock timeout, we need a dedicated call
// 'call SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.locks.waitTimeout', '3')'
return false;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public String getCurrentTimestampSelectString() {
return "values current timestamp";
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public LimitHandler getLimitHandler() {
return limitHandler;
}
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new DB2IdentityColumnSupport();
}
@Override
public boolean doesReadCommittedCauseWritersToBlockReaders() {
//TODO: check this
return true;
}
@Override
public boolean supportsParametersInInsertSelect() {
//TODO: check this
return true;
}
@Override
public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() {
return false;
}
@Override
public boolean supportsTupleDistinctCounts() {
//checked on Derby 10.14
return false;
}
@Override
public boolean supportsOrderByInSubquery() {
// As of version 10.5 Derby supports OFFSET and FETCH as well as ORDER BY in subqueries
return getVersion().isSameOrAfter( 10, 5 );
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
.getJdbcTypeRegistry();
if ( getVersion().isBefore( 10, 7 ) ) {
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, SmallIntJdbcType.INSTANCE );
}
jdbcTypeRegistry.addDescriptor( Types.NUMERIC, DecimalJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( Types.TIMESTAMP_WITH_TIMEZONE, TimestampJdbcType.INSTANCE );
// Derby requires a custom binder for binding untyped nulls that resolves the type through the statement
typeContributions.contributeJdbcType( ObjectNullResolvingJdbcType.INSTANCE );
// Until we remove StandardBasicTypes, we have to keep this
typeContributions.contributeType(
new JavaObjectType(
ObjectNullResolvingJdbcType.INSTANCE,
typeContributions.getTypeConfiguration()
.getJavaTypeRegistry()
.getDescriptor( Object.class )
)
);
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsLobValueChangePropagation() {
return false;
}
@Override
public boolean supportsUnboundedLobLocatorMaterialization() {
return false;
}
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return (sqlException, message, sql) -> {
final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException );
// final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
if ( "40XL1".equals( sqlState ) || "40XL2".equals( sqlState ) ) {
throw new LockTimeoutException( message, sqlException, sql );
}
return null;
};
}
@Override
public void appendDatetimeFormat(SqlAppender appender, String format) {
throw new UnsupportedOperationException("format() function not supported on Derby");
}
@Override
protected void registerDefaultKeywords() {
super.registerDefaultKeywords();
registerKeyword( "ADD" );
registerKeyword( "ALL" );
registerKeyword( "ALLOCATE" );
registerKeyword( "ALTER" );
registerKeyword( "AND" );
registerKeyword( "ANY" );
registerKeyword( "ARE" );
registerKeyword( "AS" );
registerKeyword( "ASC" );
registerKeyword( "ASSERTION" );
registerKeyword( "AT" );
registerKeyword( "AUTHORIZATION" );
registerKeyword( "AVG" );
registerKeyword( "BEGIN" );
registerKeyword( "BETWEEN" );
registerKeyword( "BIT" );
registerKeyword( "BOOLEAN" );
registerKeyword( "BOTH" );
registerKeyword( "BY" );
registerKeyword( "CALL" );
registerKeyword( "CASCADE" );
registerKeyword( "CASCADED" );
registerKeyword( "CASE" );
registerKeyword( "CAST" );
registerKeyword( "CHAR" );
registerKeyword( "CHARACTER" );
registerKeyword( "CHECK" );
registerKeyword( "CLOSE" );
registerKeyword( "COLLATE" );
registerKeyword( "COLLATION" );
registerKeyword( "COLUMN" );
registerKeyword( "COMMIT" );
registerKeyword( "CONNECT" );
registerKeyword( "CONNECTION" );
registerKeyword( "CONSTRAINT" );
registerKeyword( "CONSTRAINTS" );
registerKeyword( "CONTINUE" );
registerKeyword( "CONVERT" );
registerKeyword( "CORRESPONDING" );
registerKeyword( "COUNT" );
registerKeyword( "CREATE" );
registerKeyword( "CURRENT" );
registerKeyword( "CURRENT_DATE" );
registerKeyword( "CURRENT_TIME" );
registerKeyword( "CURRENT_TIMESTAMP" );
registerKeyword( "CURRENT_USER" );
registerKeyword( "CURSOR" );
registerKeyword( "DEALLOCATE" );
registerKeyword( "DEC" );
registerKeyword( "DECIMAL" );
registerKeyword( "DECLARE" );
registerKeyword( "DEFERRABLE" );
registerKeyword( "DEFERRED" );
registerKeyword( "DELETE" );
registerKeyword( "DESC" );
registerKeyword( "DESCRIBE" );
registerKeyword( "DIAGNOSTICS" );
registerKeyword( "DISCONNECT" );
registerKeyword( "DISTINCT" );
registerKeyword( "DOUBLE" );
registerKeyword( "DROP" );
registerKeyword( "ELSE" );
registerKeyword( "END" );
registerKeyword( "ENDEXEC" );
registerKeyword( "ESCAPE" );
registerKeyword( "EXCEPT" );
registerKeyword( "EXCEPTION" );
registerKeyword( "EXEC" );
registerKeyword( "EXECUTE" );
registerKeyword( "EXISTS" );
registerKeyword( "EXPLAIN" );
registerKeyword( "EXTERNAL" );
registerKeyword( "FALSE" );
registerKeyword( "FETCH" );
registerKeyword( "FIRST" );
registerKeyword( "FLOAT" );
registerKeyword( "FOR" );
registerKeyword( "FOREIGN" );
registerKeyword( "FOUND" );
registerKeyword( "FROM" );
registerKeyword( "FULL" );
registerKeyword( "FUNCTION" );
registerKeyword( "GET" );
registerKeyword( "GET_CURRENT_CONNECTION" );
registerKeyword( "GLOBAL" );
registerKeyword( "GO" );
registerKeyword( "GOTO" );
registerKeyword( "GRANT" );
registerKeyword( "GROUP" );
registerKeyword( "HAVING" );
registerKeyword( "HOUR" );
registerKeyword( "IDENTITY" );
registerKeyword( "IMMEDIATE" );
registerKeyword( "IN" );
registerKeyword( "INDICATOR" );
registerKeyword( "INITIALLY" );
registerKeyword( "INNER" );
registerKeyword( "INOUT" );
registerKeyword( "INPUT" );
registerKeyword( "INSENSITIVE" );
registerKeyword( "INSERT" );
registerKeyword( "INT" );
registerKeyword( "INTEGER" );
registerKeyword( "INTERSECT" );
registerKeyword( "INTO" );
registerKeyword( "IS" );
registerKeyword( "ISOLATION" );
registerKeyword( "JOIN" );
registerKeyword( "KEY" );
registerKeyword( "LAST" );
registerKeyword( "LEFT" );
registerKeyword( "LIKE" );
registerKeyword( "LONGINT" );
registerKeyword( "LOWER" );
registerKeyword( "LTRIM" );
registerKeyword( "MATCH" );
registerKeyword( "MAX" );
registerKeyword( "MIN" );
registerKeyword( "MINUTE" );
registerKeyword( "NATIONAL" );
registerKeyword( "NATURAL" );
registerKeyword( "NCHAR" );
registerKeyword( "NVARCHAR" );
registerKeyword( "NEXT" );
registerKeyword( "NO" );
registerKeyword( "NOT" );
registerKeyword( "NULL" );
registerKeyword( "NULLIF" );
registerKeyword( "NUMERIC" );
registerKeyword( "OF" );
registerKeyword( "ON" );
registerKeyword( "ONLY" );
registerKeyword( "OPEN" );
registerKeyword( "OPTION" );
registerKeyword( "OR" );
registerKeyword( "ORDER" );
registerKeyword( "OUT" );
registerKeyword( "OUTER" );
registerKeyword( "OUTPUT" );
registerKeyword( "OVERLAPS" );
registerKeyword( "PAD" );
registerKeyword( "PARTIAL" );
registerKeyword( "PREPARE" );
registerKeyword( "PRESERVE" );
registerKeyword( "PRIMARY" );
registerKeyword( "PRIOR" );
registerKeyword( "PRIVILEGES" );
registerKeyword( "PROCEDURE" );
registerKeyword( "PUBLIC" );
registerKeyword( "READ" );
registerKeyword( "REAL" );
registerKeyword( "REFERENCES" );
registerKeyword( "RELATIVE" );
registerKeyword( "RESTRICT" );
registerKeyword( "REVOKE" );
registerKeyword( "RIGHT" );
registerKeyword( "ROLLBACK" );
registerKeyword( "ROWS" );
registerKeyword( "RTRIM" );
registerKeyword( "SCHEMA" );
registerKeyword( "SCROLL" );
registerKeyword( "SECOND" );
registerKeyword( "SELECT" );
registerKeyword( "SESSION_USER" );
registerKeyword( "SET" );
registerKeyword( "SMALLINT" );
registerKeyword( "SOME" );
registerKeyword( "SPACE" );
registerKeyword( "SQL" );
registerKeyword( "SQLCODE" );
registerKeyword( "SQLERROR" );
registerKeyword( "SQLSTATE" );
registerKeyword( "SUBSTR" );
registerKeyword( "SUBSTRING" );
registerKeyword( "SUM" );
registerKeyword( "SYSTEM_USER" );
registerKeyword( "TABLE" );
registerKeyword( "TEMPORARY" );
registerKeyword( "TIMEZONE_HOUR" );
registerKeyword( "TIMEZONE_MINUTE" );
registerKeyword( "TO" );
registerKeyword( "TRAILING" );
registerKeyword( "TRANSACTION" );
registerKeyword( "TRANSLATE" );
registerKeyword( "TRANSLATION" );
registerKeyword( "TRUE" );
registerKeyword( "UNION" );
registerKeyword( "UNIQUE" );
registerKeyword( "UNKNOWN" );
registerKeyword( "UPDATE" );
registerKeyword( "UPPER" );
registerKeyword( "USER" );
registerKeyword( "USING" );
registerKeyword( "VALUES" );
registerKeyword( "VARCHAR" );
registerKeyword( "VARYING" );
registerKeyword( "VIEW" );
registerKeyword( "WHENEVER" );
registerKeyword( "WHERE" );
registerKeyword( "WITH" );
registerKeyword( "WORK" );
registerKeyword( "WRITE" );
registerKeyword( "XML" );
registerKeyword( "XMLEXISTS" );
registerKeyword( "XMLPARSE" );
registerKeyword( "XMLSERIALIZE" );
registerKeyword( "YEAR" );
}
/**
* {@inheritDoc}
* <p>
* From Derby docs:
* <pre>
* The DECLARE GLOBAL TEMPORARY TABLE statement defines a temporary table for the current connection.
* </pre>
*
* {@link DB2Dialect} returns a {@link GlobalTemporaryTableMutationStrategy} that
* will make temporary tables created at startup and hence unavailable for subsequent connections.<br/>
* see HHH-10238.
*/
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableMutationStrategy(
TemporaryTable.createIdTable(
rootEntityDescriptor,
basename -> "session." + TemporaryTable.ID_TABLE_PREFIX + basename,
this,
runtimeModelCreationContext
),
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new LocalTemporaryTableInsertStrategy(
TemporaryTable.createEntityTable(
rootEntityDescriptor,
name -> "session." + TemporaryTable.ENTITY_TABLE_PREFIX + name,
this,
runtimeModelCreationContext
),
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public TemporaryTableKind getSupportedTemporaryTableKind() {
return TemporaryTableKind.LOCAL;
}
@Override
public String getTemporaryTableCreateOptions() {
return "not logged";
}
@Override
public boolean supportsTemporaryTablePrimaryKey() {
return false;
}
@Override
public String getTemporaryTableCreateCommand() {
return "declare global temporary table";
}
@Override
public BeforeUseAction getTemporaryTableBeforeUseAction() {
return BeforeUseAction.CREATE;
}
@Override
public boolean supportsPartitionBy() {
return false;
}
@Override
public boolean supportsWindowFunctions() {
// It seems at least the row_number function is supported as of 10.4
return getVersion().isSameOrAfter( 10, 4 );
}
@Override
public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData)
throws SQLException {
builder.setAutoQuoteInitialUnderscore(true);
return super.buildIdentifierHelper(builder, dbMetaData);
}
}

View File

@ -0,0 +1,299 @@
/*
* 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.community.dialect;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.sqm.BinaryArithmeticOperator;
import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
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.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
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.predicate.BooleanExpressionPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.select.QueryPart;
import org.hibernate.sql.exec.spi.JdbcOperation;
/**
* A SQL AST translator for Derby.
*
* @author Christian Beikov
*/
public class DerbyLegacySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
public DerbyLegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
super( sessionFactory, statement );
}
@Override
protected void renderExpressionAsClauseItem(Expression expression) {
expression.accept( this );
}
@Override
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
final boolean isNegated = booleanExpressionPredicate.isNegated();
if ( isNegated ) {
appendSql( "not(" );
}
booleanExpressionPredicate.getExpression().accept( this );
if ( isNegated ) {
appendSql( CLOSE_PARENTHESIS );
}
}
// Derby does not allow CASE expressions where all result arms contain plain parameters.
// At least one result arm must provide some type context for inference,
// so we cast the first result arm if we encounter this condition
@Override
protected void visitAnsiCaseSearchedExpression(
CaseSearchedExpression caseSearchedExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) {
final List<CaseSearchedExpression.WhenFragment> whenFragments = caseSearchedExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSearchedExpression(
caseSearchedExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer );
}
}
@Override
protected void visitAnsiCaseSimpleExpression(
CaseSimpleExpression caseSimpleExpression,
Consumer<Expression> resultRenderer) {
if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) {
final List<CaseSimpleExpression.WhenFragment> whenFragments = caseSimpleExpression.getWhenFragments();
final Expression firstResult = whenFragments.get( 0 ).getResult();
super.visitAnsiCaseSimpleExpression(
caseSimpleExpression,
e -> {
if ( e == firstResult ) {
renderCasted( e );
}
else {
resultRenderer.accept( e );
}
}
);
}
else {
super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer );
}
}
@Override
protected String getForUpdate() {
return " for update";
}
@Override
protected String getForShare(int timeoutMillis) {
return " for read only";
}
@Override
protected String getForUpdateWithClause() {
return " with rs";
}
@Override
public void visitCteContainer(CteContainer cteContainer) {
if ( cteContainer.isWithRecursive() ) {
throw new IllegalArgumentException( "Recursive CTEs can't be emulated" );
}
super.visitCteContainer( cteContainer );
}
@Override
protected void renderSearchClause(CteStatement cte) {
// Derby does not support this, but it's just a hint anyway
}
@Override
protected void renderCycleClause(CteStatement cte) {
// Derby does not support this, but it can be emulated
}
@Override
public void visitOffsetFetchClause(QueryPart queryPart) {
// Derby only supports the OFFSET and FETCH clause with ROWS
assertRowsOnlyFetchClauseType( queryPart );
if ( supportsOffsetFetchClause() ) {
renderOffsetFetchClause( queryPart, true );
}
else if ( !getClauseStack().isEmpty() ) {
throw new IllegalArgumentException( "Can't render offset and fetch clause for subquery" );
}
}
@Override
protected void renderFetchExpression(Expression fetchExpression) {
if ( supportsParameterOffsetFetchExpression() ) {
super.renderFetchExpression( fetchExpression );
}
else {
renderExpressionAsLiteral( fetchExpression, getJdbcParameterBindings() );
}
}
@Override
protected void renderOffsetExpression(Expression offsetExpression) {
if ( supportsParameterOffsetFetchExpression() ) {
super.renderOffsetExpression( offsetExpression );
}
else {
renderExpressionAsLiteral( offsetExpression, getJdbcParameterBindings() );
}
}
@Override
protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) {
renderComparisonEmulateIntersect( lhs, operator, rhs );
}
@Override
protected void renderSelectExpression(Expression expression) {
renderSelectExpressionWithCastedOrInlinedPlainParameters( expression );
}
@Override
protected void renderSelectTupleComparison(
List<SqlSelection> lhsExpressions,
SqlTuple tuple,
ComparisonOperator operator) {
emulateSelectTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
}
@Override
protected void renderPartitionItem(Expression expression) {
if ( expression instanceof Literal ) {
appendSql( "'0'" );
}
else if ( expression instanceof Summarization ) {
Summarization summarization = (Summarization) expression;
appendSql( summarization.getKind().sqlText() );
appendSql( OPEN_PARENTHESIS );
renderCommaSeparated( summarization.getGroupings() );
appendSql( CLOSE_PARENTHESIS );
}
else {
expression.accept( this );
}
}
@Override
public void visitInListPredicate(InListPredicate inListPredicate) {
final List<Expression> listExpressions = inListPredicate.getListExpressions();
if ( listExpressions.isEmpty() ) {
appendSql( "1=0" );
return;
}
final Expression testExpression = inListPredicate.getTestExpression();
if ( isParameter( testExpression ) ) {
renderCasted( testExpression );
if ( inListPredicate.isNegated() ) {
appendSql( " not" );
}
appendSql( " in(" );
renderCommaSeparated( listExpressions );
appendSql( CLOSE_PARENTHESIS );
}
else {
super.visitInListPredicate( inListPredicate );
}
}
@Override
protected boolean supportsRowValueConstructorSyntax() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInInList() {
return false;
}
@Override
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}
@Override
protected String getFromDual() {
return " from (values 0) dual";
}
@Override
protected String getFromDualForSelectOnly() {
return getFromDual();
}
@Override
protected boolean needsRowsToSkip() {
return !supportsOffsetFetchClause();
}
@Override
protected boolean needsMaxRows() {
return !supportsOffsetFetchClause();
}
private boolean supportsParameterOffsetFetchExpression() {
return getDialect().getVersion().isSameOrAfter( 10, 6 );
}
private boolean supportsOffsetFetchClause() {
// Before version 10.5 Derby didn't support OFFSET and FETCH
return getDialect().getVersion().isSameOrAfter( 10, 5 );
}
@Override
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
final BinaryArithmeticOperator operator = arithmeticExpression.getOperator();
if ( operator == BinaryArithmeticOperator.MODULO ) {
append( "mod" );
appendSql( OPEN_PARENTHESIS );
arithmeticExpression.getLeftHandOperand().accept( this );
appendSql( ',' );
arithmeticExpression.getRightHandOperand().accept( this );
appendSql( CLOSE_PARENTHESIS );
}
else {
appendSql( OPEN_PARENTHESIS );
render( arithmeticExpression.getLeftHandOperand(), SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
appendSql( arithmeticExpression.getOperator().getOperatorSqlTextString() );
render( arithmeticExpression.getRightHandOperand(), SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
appendSql( CLOSE_PARENTHESIS );
}
}
}

View File

@ -0,0 +1,93 @@
/*
* 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.community.dialect;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.query.spi.Limit;
import static org.junit.Assert.assertEquals;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
/**
* Testing of patched support for Derby limit and offset queries; see HHH-3972
*
* @author Evan Leonard
*/
public class DerbyLegacyDialectTestCase extends BaseUnitTestCase {
@Test
@TestForIssue( jiraKey = "HHH-3972" )
public void testInsertLimitClause() {
final int limit = 50;
final String input = "select * from tablename t where t.cat = 5";
final String expected = "select * from tablename t where t.cat = 5 fetch first " + limit + " rows only";
final String actual = new DerbyLegacyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( 0, limit ) );
assertEquals( expected, actual );
}
@Test
@TestForIssue( jiraKey = "HHH-3972" )
public void testInsertLimitWithOffsetClause() {
final int limit = 50;
final int offset = 200;
final String input = "select * from tablename t where t.cat = 5";
final String expected = "select * from tablename t where t.cat = 5 offset " + offset + " rows fetch next " + limit + " rows only";
final String actual = new DerbyLegacyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
assertEquals( expected, actual );
}
@Test
@TestForIssue( jiraKey = "HHH-3972" )
public void testInsertLimitWithForUpdateClause() {
final int limit = 50;
final int offset = 200;
final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 for update of c11, c13";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 offset " + offset
+ " rows fetch next " + limit + " rows only for update of c11, c13";
final String actual = new DerbyLegacyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
assertEquals( expected, actual );
}
@Test
@TestForIssue( jiraKey = "HHH-3972" )
public void testInsertLimitWithWithClause() {
final int limit = 50;
final int offset = 200;
final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' with rr";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset " + offset
+ " rows fetch next " + limit + " rows only with rr";
final String actual = new DerbyLegacyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
assertEquals( expected, actual );
}
@Test
@TestForIssue( jiraKey = "HHH-3972" )
public void testInsertLimitWithForUpdateAndWithClauses() {
final int limit = 50;
final int offset = 200;
final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' for update of c11,c13 with rr";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset " + offset
+ " rows fetch next " + limit + " rows only for update of c11,c13 with rr";
final String actual = new DerbyLegacyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
assertEquals( expected, actual );
}
private Limit toRowSelection(int firstRow, int maxRows) {
Limit selection = new Limit();
selection.setFirstRow( firstRow );
selection.setMaxRows( maxRows );
return selection;
}
}

View File

@ -4,11 +4,12 @@
* 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.orm.test.dialect.unit.sequence;
package org.hibernate.community.dialect.unit.sequence;
import org.hibernate.community.dialect.DerbyLegacyDialect;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.orm.test.dialect.unit.sequence.AbstractSequenceInformationExtractorTest;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
@ -22,7 +23,7 @@ public class DerbyTenFiveDialectSequenceInformationExtractorTest extends Abstrac
@Override
public Dialect getDialect() {
return new DerbyDialect( DatabaseVersion.make( 10, 5 ) );
return new DerbyLegacyDialect( DatabaseVersion.make( 10, 5 ) );
}
@Override

View File

@ -4,11 +4,12 @@
* 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.orm.test.dialect.unit.sequence;
package org.hibernate.community.dialect.unit.sequence;
import org.hibernate.community.dialect.DerbyLegacyDialect;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.orm.test.dialect.unit.sequence.AbstractSequenceInformationExtractorTest;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
@ -21,7 +22,7 @@ import org.hibernate.testing.TestForIssue;
public class DerbyTenSevenDialectSequenceInformationExtractorTest extends AbstractSequenceInformationExtractorTest {
@Override
public Dialect getDialect() {
return new DerbyDialect( DatabaseVersion.make( 10, 7 ) );
return new DerbyLegacyDialect( DatabaseVersion.make( 10, 7 ) );
}
@Override

View File

@ -4,11 +4,12 @@
* 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.orm.test.dialect.unit.sequence;
package org.hibernate.community.dialect.unit.sequence;
import org.hibernate.community.dialect.DerbyLegacyDialect;
import org.hibernate.dialect.DatabaseVersion;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
import org.hibernate.orm.test.dialect.unit.sequence.AbstractSequenceInformationExtractorTest;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
@ -21,7 +22,7 @@ import org.hibernate.testing.TestForIssue;
public class DerbyTenSixDialectSequenceInformationExtractorTest extends AbstractSequenceInformationExtractorTest {
@Override
public Dialect getDialect() {
return new DerbyDialect( DatabaseVersion.make( 10, 6 ) );
return new DerbyLegacyDialect( DatabaseVersion.make( 10, 6 ) );
}
@Override

View File

@ -516,7 +516,7 @@ public class DB2Dialect extends Dialect {
return selectNullString(sqlType);
}
static String selectNullString(int sqlType) {
public static String selectNullString(int sqlType) {
String literal;
switch ( sqlType ) {
case Types.VARCHAR:

View File

@ -95,12 +95,12 @@ public class DerbyDialect extends Dialect {
// * can't select a parameter unless wrapped
// in a cast or function call
private final LimitHandler limitHandler = getVersion().isBefore( 10, 5 )
? AbstractLimitHandler.NO_LIMIT
: new DerbyLimitHandler( getVersion().isSameOrAfter( 10, 6 ) );
private final static DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 10, 14, 2 );
private final LimitHandler limitHandler = new DerbyLimitHandler( true );
public DerbyDialect() {
this( DatabaseVersion.make( 10, 0 ) );
this( MINIMUM_VERSION);
}
public DerbyDialect(DatabaseVersion version) {
@ -114,8 +114,6 @@ public class DerbyDialect extends Dialect {
@Override
protected String columnType(int sqlTypeCode) {
switch ( sqlTypeCode ) {
case BOOLEAN:
return getVersion().isBefore( 10, 7 ) ? "smallint" : super.columnType( sqlTypeCode );
case TINYINT:
//no tinyint
return "smallint";
@ -210,13 +208,6 @@ public class DerbyDialect extends Dialect {
return 31;
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return getVersion().isBefore( 10, 7 )
? Types.SMALLINT
: Types.BOOLEAN;
}
@Override
public NationalizationSupport getNationalizationSupport() {
return NationalizationSupport.IMPLICIT;
@ -438,33 +429,22 @@ public class DerbyDialect extends Dialect {
@Override
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
if ( getVersion().isBefore( 10, 7 ) ) {
appender.appendSql( bool ? '1' : '0' );
}
else {
appender.appendSql( bool );
}
appender.appendSql( bool );
}
@Override
public SequenceSupport getSequenceSupport() {
return getVersion().isBefore( 10, 6 )
? super.getSequenceSupport()
: DerbySequenceSupport.INSTANCE;
return DerbySequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return getVersion().isBefore( 10, 6 )
? null
: "select sys.sysschemas.schemaname as sequence_schema,sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid=sys.sysschemas.schemaid";
return "select sys.sysschemas.schemaname as sequence_schema,sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid=sys.sysschemas.schemaid";
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return getVersion().isBefore( 10, 6 )
? SequenceInformationExtractorNoOpImpl.INSTANCE
: SequenceInformationExtractorDerbyDatabaseImpl.INSTANCE;
return SequenceInformationExtractorDerbyDatabaseImpl.INSTANCE;
}
@Override
@ -578,7 +558,7 @@ public class DerbyDialect extends Dialect {
@Override
public boolean supportsOrderByInSubquery() {
// As of version 10.5 Derby supports OFFSET and FETCH as well as ORDER BY in subqueries
return getVersion().isSameOrAfter( 10, 5 );
return true;
}
@Override
@ -586,9 +566,6 @@ public class DerbyDialect extends Dialect {
super.contributeTypes( typeContributions, serviceRegistry );
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
.getJdbcTypeRegistry();
if ( getVersion().isBefore( 10, 7 ) ) {
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, SmallIntJdbcType.INSTANCE );
}
jdbcTypeRegistry.addDescriptor( Types.NUMERIC, DecimalJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( Types.TIMESTAMP_WITH_TIMEZONE, TimestampJdbcType.INSTANCE );
@ -923,7 +900,7 @@ public class DerbyDialect extends Dialect {
@Override
public boolean supportsWindowFunctions() {
// It seems at least the row_number function is supported as of 10.4
return getVersion().isSameOrAfter( 10, 4 );
return true;
}
@Override

View File

@ -268,12 +268,12 @@ public class DerbySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlA
}
private boolean supportsParameterOffsetFetchExpression() {
return getDialect().getVersion().isSameOrAfter( 10, 6 );
return true;
}
private boolean supportsOffsetFetchClause() {
// Before version 10.5 Derby didn't support OFFSET and FETCH
return getDialect().getVersion().isSameOrAfter( 10, 5 );
return true;
}
@Override

View File

@ -28,9 +28,9 @@ public class DerbyDialectTestCase extends BaseUnitTestCase {
public void testInsertLimitClause() {
final int limit = 50;
final String input = "select * from tablename t where t.cat = 5";
final String expected = "select * from tablename t where t.cat = 5 fetch first " + limit + " rows only";
final String expected = "select * from tablename t where t.cat = 5 fetch first ? rows only";
final String actual = new DerbyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( 0, limit ) );
final String actual = new DerbyDialect().getLimitHandler().processSql( input, toRowSelection( 0, limit ) );
assertEquals( expected, actual );
}
@ -40,9 +40,9 @@ public class DerbyDialectTestCase extends BaseUnitTestCase {
final int limit = 50;
final int offset = 200;
final String input = "select * from tablename t where t.cat = 5";
final String expected = "select * from tablename t where t.cat = 5 offset " + offset + " rows fetch next " + limit + " rows only";
final String expected = "select * from tablename t where t.cat = 5 offset ? rows fetch next ? rows only";
final String actual = new DerbyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
final String actual = new DerbyDialect().getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
assertEquals( expected, actual );
}
@ -52,10 +52,9 @@ public class DerbyDialectTestCase extends BaseUnitTestCase {
final int limit = 50;
final int offset = 200;
final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 for update of c11, c13";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 offset " + offset
+ " rows fetch next " + limit + " rows only for update of c11, c13";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 offset ? rows fetch next ? rows only for update of c11, c13";
final String actual = new DerbyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
final String actual = new DerbyDialect().getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
assertEquals( expected, actual );
}
@ -65,10 +64,9 @@ public class DerbyDialectTestCase extends BaseUnitTestCase {
final int limit = 50;
final int offset = 200;
final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' with rr";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset " + offset
+ " rows fetch next " + limit + " rows only with rr";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset ? rows fetch next ? rows only with rr";
final String actual = new DerbyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
final String actual = new DerbyDialect().getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
assertEquals( expected, actual );
}
@ -78,10 +76,9 @@ public class DerbyDialectTestCase extends BaseUnitTestCase {
final int limit = 50;
final int offset = 200;
final String input = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' for update of c11,c13 with rr";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset " + offset
+ " rows fetch next " + limit + " rows only for update of c11,c13 with rr";
final String expected = "select c11 as col1, c12 as col2, c13 as col13 from t1 where flight_id between 'AA1111' and 'AA1112' offset ? rows fetch next ? rows only for update of c11,c13 with rr";
final String actual = new DerbyDialect( DatabaseVersion.make( 10, 5 ) ).getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
final String actual = new DerbyDialect().getLimitHandler().processSql( input, toRowSelection( offset, limit ) );
assertEquals( expected, actual );
}