diff --git a/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java b/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java index 50f9136e2..75b60da15 100644 --- a/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java +++ b/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java @@ -864,13 +864,12 @@ public static void serializeEnumData(OutputStream stream, ClickHouseColumn colum if (value instanceof String) { enumValue = column.getEnumConstants().value((String) value); } else if (value instanceof Number) { - enumValue = ((Number) value).intValue(); + enumValue = column.getEnumConstants().validate(((Number) value).intValue()); } else if (value instanceof Enum) { - enumValue = ((Enum)value).ordinal(); + enumValue = column.getEnumConstants().value(((Enum) value).name()); } else { throw new IllegalArgumentException("Cannot write value of class " + value.getClass() + " into column with Enum type " + column.getOriginalTypeName()); } - if (column.getDataType() == ClickHouseDataType.Enum8) { BinaryStreamUtils.writeInt8(stream, enumValue); } else if (column.getDataType() == ClickHouseDataType.Enum16) { diff --git a/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java b/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java index 02edbce58..6b56cd889 100644 --- a/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java +++ b/client-v2/src/test/java/com/clickhouse/client/api/data_formats/internal/SerializerUtilsTest.java @@ -481,6 +481,40 @@ public void testEnumSerializationUnaffectedByNullGuard() throws Exception { Assert.assertEquals(valueOut.toByteArray(), new byte[] {2}); } + + private enum Status { active, inactive } + + @Test(dataProvider = "nonNullableEnumTypes") + public void testNonMemberNumberIntoEnumThrows(String typeName) { + ClickHouseColumn column = ClickHouseColumn.of("v", typeName); + IllegalArgumentException ex = Assert.expectThrows(IllegalArgumentException.class, + () -> SerializerUtils.serializeData(new ByteArrayOutputStream(), 7, column)); + Assert.assertTrue(ex.getMessage().contains("Unknown enum value: 7"), + "Unexpected message: " + ex.getMessage()); + } + + @Test + public void testMemberNumberIntoEnumIsWritten() throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + SerializerUtils.serializeData(out, 2, ClickHouseColumn.of("v", "Enum8('B' = 1, 'S' = 2)")); + Assert.assertEquals(out.toByteArray(), new byte[] {2}); + } + + @Test + public void testJavaEnumIsWrittenAsDeclaredValueNotOrdinal() throws Exception { + ClickHouseColumn column = ClickHouseColumn.of("v", "Enum8('active' = 1, 'inactive' = 2)"); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + SerializerUtils.serializeData(out, Status.active, column); + Assert.assertEquals(out.toByteArray(), new byte[] {1}); // ordinal() would have written 0 + } + + @Test + public void testJavaEnumNotDeclaredInColumnThrows() { + ClickHouseColumn column = ClickHouseColumn.of("v", "Enum8('B' = 1, 'S' = 2)"); + Assert.assertThrows(IllegalArgumentException.class, + () -> SerializerUtils.serializeData(new ByteArrayOutputStream(), Status.active, column)); + } + @Test(dataProvider = "nestedNullableData") public void testNestedNullableRoundTrip(String typeName, Object value) throws Exception { ClickHouseColumn column = ClickHouseColumn.of("v", typeName); diff --git a/history/latest/3304.md b/history/latest/3304.md new file mode 100644 index 000000000..edd27157b --- /dev/null +++ b/history/latest/3304.md @@ -0,0 +1 @@ +- **[client-v2]** Enum8/Enum16 inserts now validate the value on the client. A number that is not a declared enum member, or a Java `Enum` constant whose name is not declared in the column, fails with `IllegalArgumentException`. A Java `Enum` is now written as the value declared for its name instead of its `ordinal()`. (https://github.com/ClickHouse/clickhouse-java/issues/3304)