HHH-15294 cockroachdb fixes

* HHH-15294 Fix setting of untyped null values in CockroachDB dialect

Solution exactly same as in PostgresqlDialect

* HHH-15294 Change CockroachDB multitable mutation strategies to CTE

Align with the Postgresql strategy

* HHH-15294 Fix missing IdentityColumnSupport in CockroachDB Dialect

* HHH-15294 Skip test for CockRoachDB due to unsupported automatic type conversion

* HHH-15294 CockroachDB doesn't support value propagation
This commit is contained in:
Karel Maesen 2022-05-27 16:22:06 +02:00 committed by Christian Beikov
parent 6728afadb7
commit e0615b13a8
4 changed files with 69 additions and 3 deletions

View File

@ -8,12 +8,14 @@ package org.hibernate.dialect;
import java.sql.DatabaseMetaData; import java.sql.DatabaseMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types;
import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAccessor;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import org.hibernate.LockMode; import org.hibernate.LockMode;
@ -21,6 +23,8 @@ import org.hibernate.LockOptions;
import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.FormatFunction; import org.hibernate.dialect.function.FormatFunction;
import org.hibernate.dialect.identity.CockroachDBIdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler; import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport; import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport;
@ -31,10 +35,16 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.sqm.NullOrdering; import org.hibernate.query.sqm.NullOrdering;
import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.sqm.TemporalUnit;
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;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.SqlAstTranslatorFactory;
@ -42,9 +52,15 @@ import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
import org.hibernate.type.descriptor.jdbc.InstantAsTimestampWithTimeZoneJdbcType; import org.hibernate.type.descriptor.jdbc.InstantAsTimestampWithTimeZoneJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcType;
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType; import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType;
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl; import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType; import org.hibernate.type.descriptor.sql.internal.Scale6IntervalSecondDdlType;
@ -84,8 +100,8 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithM
*/ */
public class CockroachDialect extends Dialect { public class CockroachDialect extends Dialect {
private static final CockroachDBIdentityColumnSupport IDENTITY_COLUMN_SUPPORT = new CockroachDBIdentityColumnSupport();
// KNOWN LIMITATIONS: // KNOWN LIMITATIONS:
// * no support for java.sql.Clob // * no support for java.sql.Clob
private final PostgreSQLDriverKind driverKind; private final PostgreSQLDriverKind driverKind;
@ -223,6 +239,23 @@ public class CockroachDialect extends Dialect {
jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonJdbcType.INSTANCE );
} }
} }
// Force Blob binding to byte[] for CockroachDB
jdbcTypeRegistry.addDescriptor( Types.BLOB, VarbinaryJdbcType.INSTANCE );
jdbcTypeRegistry.addDescriptor( Types.CLOB, VarcharJdbcType.INSTANCE );
// The next two contributions are the same as for Postgresql
typeContributions.contributeJdbcType( ObjectNullAsBinaryTypeJdbcType.INSTANCE );
// Until we remove StandardBasicTypes, we have to keep this
typeContributions.contributeType(
new JavaObjectType(
ObjectNullAsBinaryTypeJdbcType.INSTANCE,
typeContributions.getTypeConfiguration()
.getJavaTypeRegistry()
.getDescriptor( Object.class )
)
);
} }
@Override @Override
@ -296,6 +329,11 @@ public class CockroachDialect extends Dialect {
return false; return false;
} }
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return IDENTITY_COLUMN_SUPPORT;
}
@Override @Override
public boolean supportsValuesList() { public boolean supportsValuesList() {
return true; return true;
@ -362,6 +400,11 @@ public class CockroachDialect extends Dialect {
return "select sequence_name,sequence_schema,sequence_catalog,start_value,minimum_value,maximum_value,increment from information_schema.sequences"; return "select sequence_name,sequence_schema,sequence_catalog,start_value,minimum_value,maximum_value,increment from information_schema.sequences";
} }
@Override
public boolean supportsLobValueChangePropagation() {
return false;
}
@Override @Override
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() { public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
return new StandardSqlAstTranslatorFactory() { return new StandardSqlAstTranslatorFactory() {
@ -746,4 +789,18 @@ public class CockroachDialect extends Dialect {
return super.buildIdentifierHelper( builder, dbMetaData ); return super.buildIdentifierHelper( builder, dbMetaData );
} }
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new CteMutationStrategy( rootEntityDescriptor, runtimeModelCreationContext );
}
@Override
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new CteInsertStrategy( rootEntityDescriptor, runtimeModelCreationContext );
}
} }

View File

@ -8,7 +8,7 @@ package org.hibernate.dialect.identity;
import java.sql.Types; import java.sql.Types;
public class CockroachDB1920IdentityColumnSupport extends IdentityColumnSupportImpl { public class CockroachDBIdentityColumnSupport extends IdentityColumnSupportImpl {
@Override @Override
public boolean supportsIdentityColumns() { public boolean supportsIdentityColumns() {
// Full support requires setting the sql.defaults.serial_normalization=sql_sequence in CockroachDB. // Full support requires setting the sql.defaults.serial_normalization=sql_sequence in CockroachDB.

View File

@ -11,10 +11,14 @@ import java.util.Arrays;
import org.junit.Test; import org.junit.Test;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.testing.DialectChecks; import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
@ -32,6 +36,7 @@ public class MaterializedBlobTest extends BaseCoreFunctionalTestCase {
} }
@Test @Test
@SkipForDialect(value = CockroachDialect.class, comment = "Blob in CockroachDB is same as a varbinary, to assertions will fail")
public void testTypeSelection() { public void testTypeSelection() {
int index = sessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(MaterializedBlobEntity.class.getName()).getEntityMetamodel().getPropertyIndex( "theBytes" ); int index = sessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(MaterializedBlobEntity.class.getName()).getEntityMetamodel().getPropertyIndex( "theBytes" );
BasicType<?> type = (BasicType<?>) sessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(MaterializedBlobEntity.class.getName()).getEntityMetamodel().getProperties()[index].getType(); BasicType<?> type = (BasicType<?>) sessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(MaterializedBlobEntity.class.getName()).getEntityMetamodel().getProperties()[index].getType();

View File

@ -19,6 +19,7 @@ import org.hibernate.Session;
import org.hibernate.Transaction; import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.MySQLDialect;
import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException;
@ -30,6 +31,7 @@ import org.hibernate.query.Query;
import org.hibernate.testing.DialectChecks; import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test; import org.junit.Test;
@ -81,6 +83,7 @@ public class BulkManipulationTest extends BaseCoreFunctionalTestCase {
} }
@Test @Test
@SkipForDialect(value = CockroachDialect.class, comment = "https://github.com/cockroachdb/cockroach/issues/41943")
public void testUpdateWithSubquery() { public void testUpdateWithSubquery() {
Session s = openSession(); Session s = openSession();
s.beginTransaction(); s.beginTransaction();
@ -518,7 +521,8 @@ public class BulkManipulationTest extends BaseCoreFunctionalTestCase {
} }
@Test @Test
@RequiresDialectFeature( value = DialectChecks.SupportsTemporaryTableIdentity.class, comment = "The use of the native generator leads to using identity which also needs to be supported on temporary tables") @SkipForDialect(value = CockroachDialect.class, comment = "https://github.com/cockroachdb/cockroach/issues/75101")
@RequiresDialectFeature(value = DialectChecks.SupportsTemporaryTableIdentity.class, comment = "The use of the native generator leads to using identity which also needs to be supported on temporary tables")
public void testInsertIntoSuperclassPropertiesFails() { public void testInsertIntoSuperclassPropertiesFails() {
TestData data = new TestData(); TestData data = new TestData();
data.prepare(); data.prepare();