Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions hibernate-dialect/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
<junit5.version>5.9.3</junit5.version>
<log4j2.version>2.17.2</log4j2.version>

<ydb.sdk.version>2.2.6</ydb.sdk.version>
<ydb.jdbc.version>2.2.4</ydb.jdbc.version>
<ydb.sdk.version>2.3.4</ydb.sdk.version>
<ydb.jdbc.version>2.3.3</ydb.jdbc.version>
</properties>

<licenses>
Expand Down Expand Up @@ -145,6 +145,8 @@
<configuration>
<environmentVariables>
<TESTCONTAINERS_REUSE_ENABLE>true</TESTCONTAINERS_REUSE_ENABLE>
<YDB_DOCKER_FEATURE_FLAGS>enable_parameterized_decimal</YDB_DOCKER_FEATURE_FLAGS>
<YDB_DOCKER_IMAGE>cr.yandex/yc/yandex-docker-local-ydb:trunk</YDB_DOCKER_IMAGE>
</environmentVariables>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.Dialect;
Expand Down Expand Up @@ -51,33 +52,40 @@
import static org.hibernate.type.SqlTypes.VARBINARY;
import static org.hibernate.type.SqlTypes.VARCHAR;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import tech.ydb.hibernate.dialect.code.YdbJdbcCode;
import static tech.ydb.hibernate.dialect.code.YdbJdbcCode.DECIMAL_SHIFT;
import tech.ydb.hibernate.dialect.exporter.EmptyExporter;
import tech.ydb.hibernate.dialect.exporter.YdbIndexExporter;
import tech.ydb.hibernate.dialect.hint.IndexQueryHintHandler;
import tech.ydb.hibernate.dialect.hint.QueryHintHandler;
import tech.ydb.hibernate.dialect.hint.ScanQueryHintHandler;
import tech.ydb.hibernate.dialect.translator.YdbSqlAstTranslatorFactory;
import tech.ydb.hibernate.dialect.types.BigDecimalJavaType;
import tech.ydb.hibernate.dialect.types.DecimalJdbcType;
import tech.ydb.hibernate.dialect.types.InstantJavaType;
import tech.ydb.hibernate.dialect.types.InstantJdbcType;
import tech.ydb.hibernate.dialect.types.LocalDateJavaType;
import tech.ydb.hibernate.dialect.types.LocalDateJdbcType;
import tech.ydb.hibernate.dialect.types.LocalDateTimeJavaType;
import tech.ydb.hibernate.dialect.types.LocalDateTimeJdbcType;
import static tech.ydb.hibernate.dialect.types.LocalDateTimeJdbcType.JDBC_TYPE_DATETIME_CODE;
import tech.ydb.hibernate.dialect.types.Uint8JdbcType;

/**
* @author Kirill Kurdyukov
*/
public class YdbDialect extends Dialect {

private static final Exporter<ForeignKey> FOREIGN_KEY_EMPTY_EXPORTER = new EmptyExporter<>();
private static final Exporter<Constraint> UNIQUE_KEY_EMPTY_EXPORTER = new EmptyExporter<>();
private static final List<QueryHintHandler> QUERY_HINT_HANDLERS = List.of(
IndexQueryHintHandler.INSTANCE,
ScanQueryHintHandler.INSTANCE
);
private static final ConcurrentHashMap<Integer, DecimalJdbcType> DECIMAL_JDBC_TYPE_CACHE = new ConcurrentHashMap<>();

public YdbDialect(DialectResolutionInfo dialectResolutionInfo) {
super(dialectResolutionInfo);
Expand All @@ -93,7 +101,7 @@ protected String columnType(int sqlTypeCode) {
case BIGINT -> "Int64";
case REAL, FLOAT -> "Float";
case DOUBLE -> "Double";
case NUMERIC, DECIMAL -> "Decimal (22,9)"; // Fixed
case NUMERIC, DECIMAL -> "Decimal($p, $s)";
case DATE -> "Date";
case JDBC_TYPE_DATETIME_CODE -> "Datetime";
case TIME_WITH_TIMEZONE -> "TzDateTime";
Expand All @@ -117,6 +125,14 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
typeContributions.contributeJdbcType(LocalDateJdbcType.INSTANCE);
typeContributions.contributeJavaType(InstantJavaType.INSTANCE);
typeContributions.contributeJdbcType(InstantJdbcType.INSTANCE);
typeContributions.contributeJdbcType(new DecimalJdbcType(YdbJdbcCode.DECIMAL_22_9));
typeContributions.contributeJdbcType(new DecimalJdbcType(YdbJdbcCode.DECIMAL_31_9));
typeContributions.contributeJdbcType(new DecimalJdbcType(YdbJdbcCode.DECIMAL_35_0));
typeContributions.contributeJdbcType(new DecimalJdbcType(YdbJdbcCode.DECIMAL_35_9));

// custom jdbc codec
typeContributions.contributeJdbcType(Uint8JdbcType.INSTANCE);
typeContributions.contributeJavaType(BigDecimalJavaType.INSTANCE_22_9);
}

@Override
Expand All @@ -125,7 +141,33 @@ protected void registerColumnTypes(TypeContributions typeContributions, ServiceR

final DdlTypeRegistry ddlTypeRegistry = typeContributions.getTypeConfiguration().getDdlTypeRegistry();

ddlTypeRegistry.addDescriptor(new DdlTypeImpl(JDBC_TYPE_DATETIME_CODE, "Datetime", "Datetime", this));
ddlTypeRegistry.addDescriptor(new DdlTypeImpl(YdbJdbcCode.DATETIME, "Datetime", "Datetime", this));
ddlTypeRegistry.addDescriptor(new DdlTypeImpl(YdbJdbcCode.UINT8, "Uint8", "Uint8", this));
ddlTypeRegistry.addDescriptor(new DdlTypeImpl(YdbJdbcCode.DECIMAL_22_9, "Decimal(22, 9)", "Decimal(22, 9)", this));
ddlTypeRegistry.addDescriptor(new DdlTypeImpl(YdbJdbcCode.DECIMAL_31_9, "Decimal(31, 9)", "Decimal(31, 9)", this));
ddlTypeRegistry.addDescriptor(new DdlTypeImpl(YdbJdbcCode.DECIMAL_35_0, "Decimal(35, 0)", "Decimal(35, 0)", this));
ddlTypeRegistry.addDescriptor(new DdlTypeImpl(YdbJdbcCode.DECIMAL_35_9, "Decimal(35, 9)", "Decimal(35, 9)", this));
}

@Override
public JdbcType resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
JdbcTypeRegistry jdbcTypeRegistry) {
if ((jdbcTypeCode == NUMERIC || jdbcTypeCode == DECIMAL) && (precision != 0 || scale != 0)) {
int sqlCode = DECIMAL_SHIFT + (precision << 6) + scale;

return DECIMAL_JDBC_TYPE_CACHE.computeIfAbsent(sqlCode, DecimalJdbcType::new);
}

return super.resolveSqlTypeDescriptor(columnTypeName, jdbcTypeCode, precision, scale, jdbcTypeRegistry);
}

@Override
public int getDefaultDecimalPrecision() {
return 22;
}

@Override
Expand All @@ -139,11 +181,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio

functionContributions.getFunctionRegistry().register(
"current_time",
new CurrentFunction(
"current_time",
currentTime(),
localDateTimeType
)
new CurrentFunction("current_time", currentTime(), localDateTimeType)
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package tech.ydb.hibernate.dialect.code;

/**
* @author Kirill Kurdyukov
*/
public final class YdbJdbcCode {

/**
* Boolean value.
*/
public static final int BOOL = 10000;

/**
* A signed integer. Acceptable values: from -2^7 to 2^7–1. Not supported for table columns
*/
public static final int INT8 = 10001;

/**
* An unsigned integer. Acceptable values: from 0 to 2^8–1.
*/
public static final int UINT8 = 10002;

/**
* A signed integer. Acceptable values: from –2^15 to 2^15–1. Not supported for table columns
*/
public static final int INT16 = 10003;

/**
* An unsigned integer. Acceptable values: from 0 to 2^16–1. Not supported for table columns
*/
public static final int UINT16 = 10004;

/**
* A signed integer. Acceptable values: from –2^31 to 2^31–1.
*/
public static final int INT32 = 10005;

/**
* An unsigned integer. Acceptable values: from 0 to 2^32–1.
*/
public static final int UINT32 = 10006;

/**
* A signed integer. Acceptable values: from –2^63 to 2^63–1.
*/
public static final int INT64 = 10007;

/**
* An unsigned integer. Acceptable values: from 0 to 2^64–1.
*/
public static final int UINT64 = 10008;

/**
* A real number with variable precision, 4 bytes in size. Can't be used in the primary key
*/
public static final int FLOAT = 10009;

/**
* A real number with variable precision, 8 bytes in size. Can't be used in the primary key
*/
public static final int DOUBLE = 10010;

/**
* A binary data, synonym for YDB type String
*/
public static final int BYTES = 10011;

/**
* Text encoded in UTF-8, synonym for YDB type Utf8
*/
public static final int TEXT = 10012;

/**
* YSON in a textual or binary representation. Doesn't support matching, can't be used in the primary key
*/
public static final int YSON = 10013;

/**
* JSON represented as text. Doesn't support matching, can't be used in the primary key
*/
public static final int JSON = 10014;

/**
* Universally unique identifier UUID. Not supported for table columns
*/
public static final int UUID = 10015;

/**
* Date, precision to the day
*/
public static final int DATE = 10016;

/**
* Date/time, precision to the second
*/
public static final int DATETIME = 10017;

/**
* Date/time, precision to the microsecond
*/
public static final int TIMESTAMP = 10018;

/**
* Time interval (signed), precision to microseconds
*/
public static final int INTERVAL = 10019;

/**
* Date with time zone label, precision to the day
*/
public static final int TZ_DATE = 10020;

/**
* Date/time with time zone label, precision to the second
*/
public static final int TZ_DATETIME = 10021;

/**
* Date/time with time zone label, precision to the microsecond
*/
public static final int TZ_TIMESTAMP = 10022;

/**
* JSON in an indexed binary representation. Doesn't support matching, can't be used in the primary key
*/
public static final int JSON_DOCUMENT = 10023;

public static final int DECIMAL_SHIFT = (1 << 14);

/**
* <a href="https://github.com/ydb-platform/ydb-jdbc-driver/blob/v2.3.3/jdbc/src/main/java/tech/ydb/jdbc/impl/YdbTypes.java#L37-L66">link</a>
*/
public static final int DECIMAL_22_9 = DECIMAL_SHIFT + (22 << 6) + 9;

public static final int DECIMAL_31_9 = DECIMAL_SHIFT + (31 << 6) + 9;

public static final int DECIMAL_35_0 = DECIMAL_SHIFT + (35 << 6);

public static final int DECIMAL_35_9 = DECIMAL_SHIFT + (35 << 6) + 9;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package tech.ydb.hibernate.dialect.types;

import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.jdbc.JdbcType;

/**
* @author Kirill Kurdyukov
*/
public final class BigDecimalJavaType extends org.hibernate.type.descriptor.java.BigDecimalJavaType {

public static final BigDecimalJavaType INSTANCE_22_9 = new BigDecimalJavaType();

@Override
public int getDefaultSqlScale(Dialect dialect, JdbcType jdbcType) {
return 9;
}

@Override
public int getDefaultSqlPrecision(Dialect dialect, JdbcType jdbcType) {
return 22;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package tech.ydb.hibernate.dialect.types;

import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;

/**
* @author Kirill Kurdyukov
*/
public class DecimalJdbcType extends org.hibernate.type.descriptor.jdbc.DecimalJdbcType {
private final int sqlCode;

public DecimalJdbcType(int sqlCode) {
this.sqlCode = sqlCode;
}

@Override
public int getJdbcTypeCode() {
return sqlCode;
}

@Override
public <X> ValueBinder<X> getBinder(final JavaType<X> javaType) {
return new ValueBinder<>() {
@Override
public void bind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
st.setObject(index, javaType.unwrap(value, BigDecimal.class, options), sqlCode);
}

@Override
public void bind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException {
st.setObject(name, javaType.unwrap(value, BigDecimal.class, options), sqlCode);
}
};
}
}
Loading