Fix some JSON function rendering issues on TiDB

This commit is contained in:
Christian Beikov 2024-11-21 10:47:46 +01:00
parent bcd70a82c4
commit c8a66789d1
7 changed files with 56 additions and 15 deletions

View File

@ -127,7 +127,7 @@ public class MariaDBLegacyDialect extends MySQLLegacyDialect {
@Override @Override
public AggregateSupport getAggregateSupport() { public AggregateSupport getAggregateSupport() {
return getVersion().isSameOrAfter( 10, 2 ) return getVersion().isSameOrAfter( 10, 2 )
? MySQLAggregateSupport.LONGTEXT_INSTANCE ? MySQLAggregateSupport.forMariaDB( this )
: AggregateSupportImpl.INSTANCE; : AggregateSupportImpl.INSTANCE;
} }

View File

@ -392,9 +392,7 @@ public class MySQLLegacyDialect extends Dialect {
@Override @Override
public AggregateSupport getAggregateSupport() { public AggregateSupport getAggregateSupport() {
return getMySQLVersion().isSameOrAfter( 5, 7 ) return MySQLAggregateSupport.forMySQL( this );
? MySQLAggregateSupport.JSON_INSTANCE
: super.getAggregateSupport();
} }
@Deprecated @Deprecated

View File

@ -125,7 +125,7 @@ public class MariaDBDialect extends MySQLDialect {
@Override @Override
public AggregateSupport getAggregateSupport() { public AggregateSupport getAggregateSupport() {
return MySQLAggregateSupport.LONGTEXT_INSTANCE; return MySQLAggregateSupport.forMariaDB( this );
} }
@Override @Override

View File

@ -440,7 +440,7 @@ public class MySQLDialect extends Dialect {
@Override @Override
public AggregateSupport getAggregateSupport() { public AggregateSupport getAggregateSupport() {
return MySQLAggregateSupport.JSON_INSTANCE; return MySQLAggregateSupport.forMySQL( this );
} }
@Deprecated(since="6.4") @Deprecated(since="6.4")

View File

@ -5,6 +5,8 @@
package org.hibernate.dialect; package org.hibernate.dialect;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.dialect.aggregate.AggregateSupport;
import org.hibernate.dialect.aggregate.MySQLAggregateSupport;
import org.hibernate.dialect.sequence.SequenceSupport; import org.hibernate.dialect.sequence.SequenceSupport;
import org.hibernate.dialect.sequence.TiDBSequenceSupport; import org.hibernate.dialect.sequence.TiDBSequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
@ -90,6 +92,11 @@ public class TiDBDialect extends MySQLDialect {
return TiDBSequenceSupport.INSTANCE; return TiDBSequenceSupport.INSTANCE;
} }
@Override
public AggregateSupport getAggregateSupport() {
return MySQLAggregateSupport.forTiDB( this );
}
@Override @Override
public SequenceInformationExtractor getSequenceInformationExtractor() { public SequenceInformationExtractor getSequenceInformationExtractor() {
return SequenceInformationExtractorTiDBDatabaseImpl.INSTANCE; return SequenceInformationExtractorTiDBDatabaseImpl.INSTANCE;

View File

@ -4,6 +4,7 @@
*/ */
package org.hibernate.dialect.aggregate; package org.hibernate.dialect.aggregate;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Column; import org.hibernate.mapping.Column;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
@ -48,13 +49,32 @@ import static org.hibernate.type.SqlTypes.VARCHAR;
public class MySQLAggregateSupport extends AggregateSupportImpl { public class MySQLAggregateSupport extends AggregateSupportImpl {
public static final AggregateSupport JSON_INSTANCE = new MySQLAggregateSupport( true ); private static final AggregateSupport JSON_INSTANCE = new MySQLAggregateSupport( true, false );
public static final AggregateSupport LONGTEXT_INSTANCE = new MySQLAggregateSupport( false ); private static final AggregateSupport JSON_WITH_UUID_INSTANCE = new MySQLAggregateSupport( true, true );
private static final AggregateSupport LONGTEXT_INSTANCE = new MySQLAggregateSupport( false, false );
private final boolean jsonType; private final boolean jsonType;
private final boolean uuidFunctions;
public MySQLAggregateSupport(boolean jsonType) { private MySQLAggregateSupport(boolean jsonType, boolean uuidFunctions) {
this.jsonType = jsonType; this.jsonType = jsonType;
this.uuidFunctions = uuidFunctions;
}
public static AggregateSupport forMySQL(Dialect dialect) {
return dialect.getVersion().isSameOrAfter( 8 )
? JSON_WITH_UUID_INSTANCE
: dialect.getVersion().isSameOrAfter( 5, 7 )
? JSON_INSTANCE
: AggregateSupportImpl.INSTANCE;
}
public static AggregateSupport forTiDB(Dialect dialect) {
return JSON_WITH_UUID_INSTANCE;
}
public static AggregateSupport forMariaDB(Dialect dialect) {
return LONGTEXT_INSTANCE;
} }
@Override @Override
@ -92,10 +112,19 @@ public class MySQLAggregateSupport extends AggregateSupportImpl {
); );
case UUID: case UUID:
if ( column.getJdbcMapping().getJdbcType().isBinary() ) { if ( column.getJdbcMapping().getJdbcType().isBinary() ) {
return template.replace( if ( uuidFunctions ) {
placeholder, return template.replace(
"unhex(replace(json_unquote(" + queryExpression( aggregateParentReadExpression, columnExpression ) + "),'-',''))" placeholder,
); "uuid_to_bin(json_unquote(" + queryExpression( aggregateParentReadExpression, columnExpression ) + "))"
);
}
else {
return template.replace(
placeholder,
"unhex(replace(json_unquote(" + queryExpression( aggregateParentReadExpression,
columnExpression ) + "),'-',''))"
);
}
} }
// Fall-through intended // Fall-through intended
default: default:
@ -142,7 +171,7 @@ public class MySQLAggregateSupport extends AggregateSupportImpl {
} }
} }
private static String jsonCustomWriteExpression(String customWriteExpression, JdbcMapping jdbcMapping) { private String jsonCustomWriteExpression(String customWriteExpression, JdbcMapping jdbcMapping) {
final int sqlTypeCode = jdbcMapping.getJdbcType().getDefaultSqlTypeCode(); final int sqlTypeCode = jdbcMapping.getJdbcType().getDefaultSqlTypeCode();
switch ( sqlTypeCode ) { switch ( sqlTypeCode ) {
case BINARY: case BINARY:
@ -159,7 +188,12 @@ public class MySQLAggregateSupport extends AggregateSupportImpl {
return "date_format(" + customWriteExpression + ",'%Y-%m-%dT%T.%fZ')"; return "date_format(" + customWriteExpression + ",'%Y-%m-%dT%T.%fZ')";
case UUID: case UUID:
if ( jdbcMapping.getJdbcType().isBinary() ) { if ( jdbcMapping.getJdbcType().isBinary() ) {
return "regexp_replace(lower(hex(" + customWriteExpression + ")),'^(.{8})(.{4})(.{4})(.{4})(.{12})$','$1-$2-$3-$4-$5')"; if ( uuidFunctions ) {
return "bin_to_uuid(" + customWriteExpression + ")";
}
else {
return "regexp_replace(lower(hex(" + customWriteExpression + ")),'^(.{8})(.{4})(.{4})(.{4})(.{12})$','$1-$2-$3-$4-$5')";
}
} }
// Fall-through intended // Fall-through intended
default: default:

View File

@ -10,6 +10,7 @@ import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.JdbcSettings; import org.hibernate.cfg.JdbcSettings;
import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.TiDBDialect;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa; import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.Setting; import org.hibernate.testing.orm.junit.Setting;
@ -31,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
{@Setting(name = AvailableSettings.TIMEZONE_DEFAULT_STORAGE, value = "NORMALIZE"), {@Setting(name = AvailableSettings.TIMEZONE_DEFAULT_STORAGE, value = "NORMALIZE"),
@Setting(name = JdbcSettings.JDBC_TIME_ZONE, value = "+01:00")}) @Setting(name = JdbcSettings.JDBC_TIME_ZONE, value = "+01:00")})
@SkipForDialect(dialectClass = MySQLDialect.class, reason = "MySQL hangs dropping the table") @SkipForDialect(dialectClass = MySQLDialect.class, reason = "MySQL hangs dropping the table")
@SkipForDialect(dialectClass = TiDBDialect.class, reason = "Values stored in timestamp DDL type columns get the JDBC time zone offset subtracted")
public class InstantWithNormalizedTest { public class InstantWithNormalizedTest {
@Test @Test
public void test(EntityManagerFactoryScope scope) { public void test(EntityManagerFactoryScope scope) {