HHH-17696 Make Altibase Dialect compatible with Altibase 7.1 and fixes several test failures.

This commit is contained in:
yjpark 2024-02-05 15:32:45 +09:00 committed by Christian Beikov
parent 472aeb6b6d
commit 7b0e511577
10 changed files with 129 additions and 31 deletions

View File

@ -52,13 +52,13 @@ import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
/**
* An SQL dialect for Altibase 7.3 and above.
* An SQL dialect for Altibase 7.1 and above.
*
* @author Geoffrey Park
*/
public class AltibaseDialect extends Dialect {
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 7, 3 );
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 7, 1 );
@SuppressWarnings("unused")
public AltibaseDialect() {
@ -500,11 +500,6 @@ public class AltibaseDialect extends Dialect {
return false;
}
@Override
public boolean supportsInsertReturningGeneratedKeys() {
return true;
}
@Override
public boolean supportsTruncateWithCast(){
return false;
@ -535,6 +530,17 @@ public class AltibaseDialect extends Dialect {
return true;
}
@Override
public boolean supportsFromClauseInUpdate() {
return true;
}
@Override
public boolean supportsOuterJoinForUpdate() {
// "SELECT FOR UPDATE can only be used with a single-table SELECT statement"
return false;
}
@Override
public SequenceSupport getSequenceSupport() {
return AltibaseSequenceSupport.INSTANCE;
@ -560,6 +566,11 @@ public class AltibaseDialect extends Dialect {
return AltibaseLimitHandler.INSTANCE;
}
@Override
public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() {
return DmlTargetColumnQualifierSupport.TABLE_ALIAS;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
@ -580,11 +591,6 @@ public class AltibaseDialect extends Dialect {
return " cascade constraints";
}
@Override
public boolean supportsValuesListForInsert() {
return false;
}
@Override
public boolean supportsOrderByInSubquery() {
return false;
@ -628,25 +634,28 @@ public class AltibaseDialect extends Dialect {
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return (sqlException, message, sql) -> {
final int errorCode = JdbcExceptionHelper.extractErrorCode(sqlException );
if ( errorCode == 334393 || errorCode == 4164) {
// 334393 - response timeout , 4164 - query timeout.
return new LockTimeoutException(message, sqlException, sql );
final String constraintName;
switch ( JdbcExceptionHelper.extractErrorCode( sqlException ) ) {
case 334393: // response timeout
case 4164: // query timeout
return new LockTimeoutException(message, sqlException, sql );
case 69720: // unique constraint violated
constraintName = getViolatedConstraintNameExtractor().extractConstraintName( sqlException );
return new ConstraintViolationException(
message,
sqlException,
sql,
ConstraintViolationException.ConstraintKind.UNIQUE,
constraintName
);
case 200820: // Cannot insert NULL or update to NULL
case 200823: // foreign key constraint violation
case 200822: // failed on update or delete by foreign key constraint violation
constraintName = getViolatedConstraintNameExtractor().extractConstraintName( sqlException );
return new ConstraintViolationException( message, sqlException, sql, constraintName );
default:
return null;
}
// 200820 - Cannot insert NULL or update to NULL
// 69720 - Unique constraint violated
// 200823 - foreign key constraint violation
// 200822 - failed on update or delete by foreign key constraint violation
if ( errorCode == 200820 || errorCode == 69720 || errorCode == 200823 || errorCode == 200822 ) {
final String constraintName = getViolatedConstraintNameExtractor().extractConstraintName( sqlException );
return new ConstraintViolationException(message, sqlException, sql, constraintName );
}
return null;
};
}

View File

@ -10,25 +10,32 @@ package org.hibernate.community.dialect;
import java.util.List;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.query.sqm.FrameExclusion;
import org.hibernate.query.sqm.FrameKind;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.FunctionExpression;
import org.hibernate.sql.ast.tree.expression.Literal;
import org.hibernate.sql.ast.tree.expression.Over;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.ValuesTableReference;
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.QueryPart;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.update.Assignment;
import org.hibernate.sql.ast.tree.update.UpdateStatement;
import org.hibernate.sql.exec.spi.JdbcOperation;
/**
@ -141,6 +148,63 @@ public class AltibaseSqlAstTranslator<T extends JdbcOperation> extends AbstractS
emulateValuesTableReferenceColumnAliasing( tableReference );
}
@Override
protected void visitInsertStatementOnly(InsertSelectStatement statement) {
if ( statement.getConflictClause() == null || statement.getConflictClause().isDoNothing() ) {
// Render plain insert statement and possibly run into unique constraint violation
super.visitInsertStatementOnly( statement );
}
else {
visitInsertStatementEmulateMerge( statement );
}
}
protected void renderMergeUpdateClause(List<Assignment> assignments, Predicate wherePredicate) {
// In Altibase, where condition in merge can be placed next to the set clause."
appendSql( " then update" );
renderSetClause( assignments );
visitWhereClause( wherePredicate );
}
@Override
protected void renderDeleteClause(DeleteStatement statement) {
appendSql( "delete" );
final Stack<Clause> clauseStack = getClauseStack();
try {
clauseStack.push( Clause.DELETE );
renderTableReferenceIdentificationVariable( statement.getTargetTable() );
if ( statement.getFromClause().getRoots().isEmpty() ) {
appendSql( " from " );
renderDmlTargetTableExpression( statement.getTargetTable() );
}
else {
visitFromClause( statement.getFromClause() );
}
}
finally {
clauseStack.pop();
}
}
@Override
protected void renderDmlTargetTableExpression(NamedTableReference tableReference) {
super.renderDmlTargetTableExpression( tableReference );
if ( getClauseStack().getCurrent() != Clause.INSERT ) {
renderTableReferenceIdentificationVariable( tableReference );
}
}
@Override
protected void renderUpdateClause(UpdateStatement updateStatement) {
if ( updateStatement.getFromClause().getRoots().isEmpty() ) {
super.renderUpdateClause( updateStatement );
}
else {
appendSql( "update " );
renderFromClauseSpaces( updateStatement.getFromClause() );
}
}
@Override
public void visitQueryPartTableReference(QueryPartTableReference tableReference) {
emulateQueryPartTableReferenceColumnAliasing( tableReference );
@ -171,6 +235,11 @@ public class AltibaseSqlAstTranslator<T extends JdbcOperation> extends AbstractS
return false;
}
@Override
protected boolean supportsJoinsInDelete() {
return true;
}
@Override
protected boolean supportsSimpleQueryGrouping() {
return false;

View File

@ -8,11 +8,13 @@ package org.hibernate.orm.test.interfaceproxy;
import org.hibernate.Session;
import org.hibernate.community.dialect.AltibaseDialect;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.SkipForDialect;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -34,6 +36,9 @@ public class InterfaceProxyTest {
feature = DialectFeatureChecks.SupportsExpectedLobUsagePattern.class,
comment = "database/driver does not support expected LOB usage pattern"
)
@SkipForDialect(dialectClass = AltibaseDialect.class, majorVersion = 7, minorVersion = 1,
reason = "Altibase 7.1 lob column cannot be not null")
public void testInterfaceProxies(SessionFactoryScope scope) {
Document doc = new DocumentImpl();
SecureDocument doc2 = new SecureDocumentImpl();

View File

@ -19,7 +19,9 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.sql.model.MutationType;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterAll;
@ -40,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Marco Belladelli
*/
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsIdentityColumns.class)
@DomainModel( annotatedClasses = {
MutationDelegateJoinedInheritanceTest.BaseEntity.class,
MutationDelegateJoinedInheritanceTest.ChildEntity.class,

View File

@ -14,6 +14,7 @@ import java.time.temporal.ChronoUnit;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.community.dialect.AltibaseDialect;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
@ -178,6 +179,7 @@ public class GlobalJavaTimeJdbcTypeTests {
@Test
@SkipForDialect(dialectClass = OracleDialect.class, reason = "Oracle drivers truncate fractional seconds from the LocalTime", matchSubTypes = true)
@SkipForDialect(dialectClass = HANADialect.class, reason = "HANA time type does not support fractional seconds", matchSubTypes = true)
@SkipForDialect(dialectClass = AltibaseDialect.class, reason = "Altibase drivers truncate fractional seconds from the LocalTime")
void testLocalTime(SessionFactoryScope scope) {
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
final LocalTime startTime = roundToDefaultPrecision( LocalTime.now(), dialect );

View File

@ -14,6 +14,7 @@ import java.time.temporal.ChronoUnit;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.cfg.MappingSettings;
import org.hibernate.community.dialect.AltibaseDialect;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
@ -178,6 +179,7 @@ public class JavaTimeJdbcTypeTests {
@Test
@SkipForDialect(dialectClass = OracleDialect.class, reason = "Oracle drivers truncate fractional seconds from the LocalTime", matchSubTypes = true)
@SkipForDialect(dialectClass = HANADialect.class, reason = "HANA time type does not support fractional seconds", matchSubTypes = true)
@SkipForDialect(dialectClass = AltibaseDialect.class, reason = "Altibase drivers truncate fractional seconds from the LocalTime")
void testLocalTime(SessionFactoryScope scope) {
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
final LocalTime startTime = roundToDefaultPrecision( LocalTime.now(), dialect );

View File

@ -15,6 +15,7 @@ import java.time.ZonedDateTime;
import org.hibernate.annotations.FractionalSeconds;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.community.dialect.AltibaseDialect;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
@ -119,6 +120,7 @@ public class FractionalSecondsTests {
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby does not support sized timestamp")
@SkipForDialect(dialectClass = HANADialect.class, reason = "HANA does not support specifying a precision on timestamps")
@SkipForDialect(dialectClass = SybaseDialect.class, reason = "Because... Sybase...", matchSubTypes = true)
@SkipForDialect(dialectClass = AltibaseDialect.class, reason = "Altibase does not support specifying a precision on timestamps")
void testUsage0(SessionFactoryScope scope) {
final Instant start = Instant.now();
@ -142,6 +144,7 @@ public class FractionalSecondsTests {
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby does not support sized timestamp")
@SkipForDialect(dialectClass = HANADialect.class, reason = "HANA does not support specifying a precision on timestamps")
@SkipForDialect(dialectClass = SybaseDialect.class, reason = "Because... Sybase...", matchSubTypes = true)
@SkipForDialect(dialectClass = AltibaseDialect.class, reason = "Altibase does not support specifying a precision on timestamps")
void testUsage3(SessionFactoryScope scope) {
final Instant start = Instant.now();

View File

@ -16,6 +16,7 @@ import java.time.ZonedDateTime;
import org.hibernate.annotations.FractionalSeconds;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.community.dialect.AltibaseDialect;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.Dialect;
@ -121,6 +122,7 @@ public class JavaTimeFractionalSecondsTests {
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby does not support sized timestamp")
@SkipForDialect(dialectClass = HANADialect.class, reason = "HANA does not support specifying a precision on timestamps")
@SkipForDialect(dialectClass = SybaseDialect.class, reason = "Because... Sybase...", matchSubTypes = true)
@SkipForDialect(dialectClass = AltibaseDialect.class, reason = "Altibase does not support specifying a precision on timestamps")
void testUsage0(SessionFactoryScope scope) {
final Instant start = Instant.now();
@ -144,6 +146,7 @@ public class JavaTimeFractionalSecondsTests {
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby does not support sized timestamp")
@SkipForDialect(dialectClass = HANADialect.class, reason = "HANA does not support specifying a precision on timestamps")
@SkipForDialect(dialectClass = SybaseDialect.class, reason = "Because... Sybase...", matchSubTypes = true)
@SkipForDialect(dialectClass = AltibaseDialect.class, reason = "Altibase does not support specifying a precision on timestamps")
void testUsage3(SessionFactoryScope scope) {
final Instant start = Instant.now();

View File

@ -1,5 +1,6 @@
package org.hibernate.test.ucp;
import org.hibernate.community.dialect.AltibaseDialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.dialect.TiDBDialect;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
@ -9,6 +10,7 @@ import org.hibernate.testing.orm.junit.SkipForDialect;
@SkipForDialect(dialectClass = SybaseDialect.class, matchSubTypes = true, reason = "The jTDS driver doesn't implement Connection#getNetworkTimeout() so this fails")
@SkipForDialect(dialectClass = TiDBDialect.class, matchSubTypes = true, reason = "Doesn't support SERIALIZABLE isolation")
@SkipForDialect(dialectClass = AltibaseDialect.class, matchSubTypes = true, reason = "Altibase cannot change isolation level in autocommit mode")
public class UCPTransactionIsolationConfigTest extends BaseTransactionIsolationConfigTest{
@Override
protected ConnectionProvider getConnectionProviderUnderTest() {

View File

@ -235,7 +235,7 @@ dependencyResolutionManagement {
def pgsqlVersion = version "pgsql", "42.7.1"
def sybaseVersion = version "sybase", "1.3.1"
def tidbVersion = version "tidb", mysqlVersion
def altibaseVersion = version "altibase", "7.3.0.0.2"
def altibaseVersion = version "altibase", "7.3.0.0.3"
library( "h2", "com.h2database", "h2" ).versionRef( h2Version )
library( "h2gis", "org.orbisgis", "h2gis" ).versionRef( h2gisVersion )