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
public AggregateSupport getAggregateSupport() {
return getVersion().isSameOrAfter( 10, 2 )
? MySQLAggregateSupport.LONGTEXT_INSTANCE
? MySQLAggregateSupport.forMariaDB( this )
: AggregateSupportImpl.INSTANCE;
}

View File

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

View File

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

View File

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

View File

@ -5,6 +5,8 @@
package org.hibernate.dialect;
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.TiDBSequenceSupport;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
@ -90,6 +92,11 @@ public class TiDBDialect extends MySQLDialect {
return TiDBSequenceSupport.INSTANCE;
}
@Override
public AggregateSupport getAggregateSupport() {
return MySQLAggregateSupport.forTiDB( this );
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return SequenceInformationExtractorTiDBDatabaseImpl.INSTANCE;

View File

@ -4,6 +4,7 @@
*/
package org.hibernate.dialect.aggregate;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.Column;
import org.hibernate.metamodel.mapping.JdbcMapping;
@ -48,13 +49,32 @@ import static org.hibernate.type.SqlTypes.VARCHAR;
public class MySQLAggregateSupport extends AggregateSupportImpl {
public static final AggregateSupport JSON_INSTANCE = new MySQLAggregateSupport( true );
public static final AggregateSupport LONGTEXT_INSTANCE = new MySQLAggregateSupport( false );
private static final AggregateSupport JSON_INSTANCE = new MySQLAggregateSupport( true, 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 uuidFunctions;
public MySQLAggregateSupport(boolean jsonType) {
private MySQLAggregateSupport(boolean jsonType, boolean uuidFunctions) {
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
@ -92,10 +112,19 @@ public class MySQLAggregateSupport extends AggregateSupportImpl {
);
case UUID:
if ( column.getJdbcMapping().getJdbcType().isBinary() ) {
return template.replace(
placeholder,
"unhex(replace(json_unquote(" + queryExpression( aggregateParentReadExpression, columnExpression ) + "),'-',''))"
);
if ( uuidFunctions ) {
return template.replace(
placeholder,
"uuid_to_bin(json_unquote(" + queryExpression( aggregateParentReadExpression, columnExpression ) + "))"
);
}
else {
return template.replace(
placeholder,
"unhex(replace(json_unquote(" + queryExpression( aggregateParentReadExpression,
columnExpression ) + "),'-',''))"
);
}
}
// Fall-through intended
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();
switch ( sqlTypeCode ) {
case BINARY:
@ -159,7 +188,12 @@ public class MySQLAggregateSupport extends AggregateSupportImpl {
return "date_format(" + customWriteExpression + ",'%Y-%m-%dT%T.%fZ')";
case UUID:
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
default:

View File

@ -10,6 +10,7 @@ import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.JdbcSettings;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.TiDBDialect;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
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 = JdbcSettings.JDBC_TIME_ZONE, value = "+01:00")})
@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 {
@Test
public void test(EntityManagerFactoryScope scope) {