Skip to content

[client-v2] Validate Enum8/Enum16 values on insert - #3312

Open
jaya232 wants to merge 1 commit into
ClickHouse:mainfrom
jaya232:fix/3304-enum-serialization-validation
Open

jaya232 wants to merge 1 commit into
ClickHouse:mainfrom
jaya232:fix/3304-enum-serialization-validation

Conversation

@jaya232

@jaya232 jaya232 commented Nov 7, 2026 •

Copy link
Copy Markdown

Closes #3304

Problem

SerializerUtils.serializeEnumData() only validated the String form of an Enum8/Enum16 value. Two other paths wrote data without checking:

  • a Number was written as-is, even if it is not a member of the column's enum (e.g. 7 into Enum8('active' = 1, 'inactive' = 2))
  • a Java Enum was written using ordinal(), which is the declaration index in Java and not the value declared in the column (Status.active ended up as 0 instead of 1)

The server accepts such rows, but reading them back as text then fails with UNKNOWN_ELEMENT_OF_ENUM.

Fix

  • Number: validated with ClickHouseEnum.validate(int), so an unknown value fails on the client with Unknown enum value: 7
  • Java Enum: mapped by name with ClickHouseEnum.value(name()), so it is written as the declared value, and a constant that is not declared in the column fails

Tests

Added to SerializerUtilsTest:

  • non-member number into Enum8 and Enum16 throws
  • member number is written as is
  • Java enum is written as the declared value, not the ordinal
  • Java enum not declared in the column throws

The first, third and fourth tests failed before the change and pass now. SerializerUtils* tests in client-v2 pass locally. The enum values in the existing integration tests (valid members, negative values and 0) still go through the same path, but I did not run the integration tests (no Docker).

Compatibility

Behavior change: values that used to be written silently (non-member numbers, Java enums via ordinal()) now throw IllegalArgumentException. Valid strings, valid member numbers and valid Java enum names are unchanged.

Added history/latest/3304.md.


Note

Medium Risk
Behavior change on the insert path: code that relied on silent non-member numbers or Java enum ordinals will now throw at serialization time, though valid strings and declared member values are unchanged.

Overview
Enum8/Enum16 serialization in SerializerUtils.serializeEnumData() now rejects invalid inserts on the client instead of writing bytes the server accepts but that break reads later.

Numeric values go through ClickHouseEnum.validate(int) so undeclared integers (e.g. 7 on Enum8('B' = 1, 'S' = 2)) throw IllegalArgumentException with Unknown enum value: … instead of being written raw.

Java Enum constants are resolved by name via ClickHouseEnum.value(name()), so the wire value matches the column declaration (e.g. 'active' = 1), not Java ordinal(). Constants whose names are not in the column definition also fail on insert.

Unit tests in SerializerUtilsTest cover invalid numbers, valid member numbers, Java enum mapping, and undeclared Java enum names. Changelog entry added in history/latest/3304.md.

Reviewed by Cursor Bugbot for commit daa3d48. Bugbot is set up for automated code reviews on this repo. Configure here.

@jaya232
jaya232 force-pushed the fix/3304-enum-serialization-validation branch from eabfd41 to daa3d48 Compare November 7, 2026 06:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[client-v2] Enum8/Enum16 insert accepts a non-member integer and uses Enum.ordinal(), silently storing values that are not enum members

1 participant