ClickHouse / clickhouse-go

Golang driver for ClickHouse
Apache License 2.0
2.88k stars 553 forks source link

lib/column/enum.go can't parse specific enum definitions #1299

Closed tanayabh closed 1 month ago

tanayabh commented 4 months ago

Observed

I have an enum column in my table will this column definition retention_policy Enum ('raw:48h,1h:63d,1d:5y' = 1, 'raw:8h,1m:48h,1h:63d,1d:5y' = 2) CODEC (ZSTD),. When trying to batch insert values in this table via batch, err = scope.Prepare(INSERT INTO ) the driver hits this code path where chType is set to Enum8('raw:48h,1h:63d,1d:5y' = 1, 'raw:8h,1m:48h,1h:63d,1d:5y' = 2) and then it trips on this split on first comma in https://github.com/ClickHouse/clickhouse-go/blob/28fd6a4954a5dbf09b7dcc0fcce597beb2dd0b58/lib/column/enum.go#L54.

Expected behaviour

The java driver has no such problems and as far as I can tell any valid string can be the key in an enum column.

Environment

tanayabh commented 4 months ago

I was able to fix this in my code by vendoring the library and changing https://github.com/ClickHouse/clickhouse-go/blob/28fd6a4954a5dbf09b7dcc0fcce597beb2dd0b58/lib/column/enum.go#L54 to use

// splitIgnoringNestedCommas splits the input string by commas, ignoring commas within nested single quotes.
func splitIgnoringNestedCommas(input string) []string {
    var result []string
    var sb strings.Builder
    inQuotes := false

    for _, char := range input {
        switch char {
        case '\'':
            inQuotes = !inQuotes
            sb.WriteRune(char)
        case ',':
            if inQuotes {
                sb.WriteRune(char)
            } else {
                result = append(result, sb.String())
                sb.Reset()
            }
        default:
            sb.WriteRune(char)
        }
    }

    // Append the last segment if any
    if sb.Len() > 0 {
        result = append(result, sb.String())
    }

    return result
}
jkaflik commented 4 months ago

@tanayabh would you like to submit a PR?