private static List<String> generateRow(List<Column> columns, int rowIndex, LocalDateTime seriesStart,
                                            Duration seriesInterval, boolean useSeries, Random rand) {
        List<String> row = new ArrayList<>();
        for (Column col : columns) {
            String[] colDef = col.type.split("[\\s\\(\\)]+");

            ClickHouseDataTypesShort chType;
            try {
                chType = ClickHouseDataTypesShort.valueOf(colDef[0]);
            } catch (IllegalArgumentException e) {
                LOG.error("Unknown type: " + colDef[0]);
                chType = ClickHouseDataTypesShort.String; // Default to String if unknown
            }

            if (chType.hasParameters()) {
                // Handle types with parameters (e.g., Decimal, Array, etc.)
                String param = colDef[1];
                if (param.startsWith("(") && param.endsWith(")")) {
                    param = param.substring(1, param.length() - 1);
                }
                String[] params = param.split(",");
                if (params.length > 0) {
                    // Use the first parameter for generating values
                    col.type = chType.name() + "(" + params[0] + ")";
                }
            }

            switch (chType) {
                case Int8:
                    row.add(String.valueOf(rand.nextInt(256) - 128));
                    break;
                case UInt8:
                    row.add(String.valueOf(rand.nextInt(256)));
                    break;
                case Int16:
                    row.add(String.valueOf(rand.nextInt(65536) - 32768));
                    break;
                case UInt16:
                    row.add(String.valueOf(rand.nextInt(65536)));
                    break;
                case Int32:
                    row.add(String.valueOf(rand.nextInt()));
                    break;
                case UInt32:
                    row.add(String.valueOf(Math.abs(rand.nextLong())));
                    break;
                case Int64:
                    row.add(String.valueOf(rand.nextLong()));
                    break;
                case UInt64:
                    row.add(String.valueOf(Math.abs(rand.nextLong())));
                    break;
                case Float32:
                    row.add(String.valueOf(rand.nextFloat()));
                    break;
                case Float64:
                    row.add(String.valueOf(rand.nextDouble()));
                    break;
                case String:
                    row.add(randomString(10, rand));
                    break;
                case DateTime:
                case DateTime32:
                case DateTime64:
                case Date:
                    if (useSeries && seriesStart != null) {
                        LocalDateTime dateTime = seriesStart.plus(seriesInterval.multipliedBy(rowIndex));
                        row.add(dateTime.format(chType == ClickHouseDataTypesShort.Date ? DATE_FORMATTER : DATETIME_FORMATTER));
                    } else {
                        LocalDateTime dateTime = LocalDateTime.now().minusDays(rand.nextInt(365));
                        row.add(dateTime.format(chType == ClickHouseDataTypesShort.Date ? DATE_FORMATTER : DATETIME_FORMATTER));
                    }
                    break;
                case Decimal:
                    if (colDef.length > 1) {
                        int scale = 10;
                        double value = rand.nextDouble() * Math.pow(10, scale);
                        row.add(String.format("%." + scale + "f", value));
                    } else {
                        row.add("0.0");
                    }
                    break;
                default:
                    // Handle other types as needed
                    row.add("NULL");

            }
        }

        return row;
    }
Formatter for the DateTime type with nanoseconds.
performance/src/main/java/com/clickhouse/benchmark/data/DataSetGenerator.java