RowBinary

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/interfaces/formats/RowBinary/RowBinary.md)

|  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- |
| Input Output Alias|  |  |  | | --- | --- | --- | | ✔ ✔  | | | | | |

## Description[​](#description "Direct link to Description")

The `RowBinary` format parses data by row in binary format.
Rows and values are listed consecutively, without separators.
Because data is in the binary format the delimiter after `FORMAT RowBinary` is strictly specified as follows:

- Any number of whitespaces:
  - `' '` (space - code `0x20`)
  - `'\t'` (tab - code `0x09`)
  - `'\f'` (form feed - code `0x0C`)
- Followed by exactly one new line sequence:
  - Windows style `"\r\n"`
  - or Unix style `'\n'`
- Immediately followed by binary data.

Note

This format is less efficient than the [Native](/docs/interfaces/formats/Native) format since it is row-based.

## Data types wire format[​](#data-types-wire-format "Direct link to Data types wire format")

Tip

Most of the queries provided in the examples can be executed with curl with a file output.

```
curl -XPOST "http://localhost:8123?default_format=RowBinary" \
  --data-binary "SELECT 42 :: UInt32"  > out.bin
```

Then, the data can be examined with a hex editor.

### Unsigned LEB128 (Little Endian Base 128)[​](#unsigned-leb128 "Direct link to Unsigned LEB128 (Little Endian Base 128)")

An **unsigned little-endian** variable-width integer encoding used to encode the length of variable-size data types such as `String`, `Array` and `Map`. A sample implementation can be found on the [LEB128 wiki page](https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer).

### (U)Int8, (U)Int16, (U)Int32, (U)Int64, (U)Int128, (U)Int256[​](#integer-types "Direct link to (U)Int8, (U)Int16, (U)Int32, (U)Int64, (U)Int128, (U)Int256")

All integer types are encoded with an appropriate number of bytes as **little-endian**. Signed types (`Int8` through `Int256`) use **two's complement** representation. Most languages support extracting such integers from byte arrays, using either built-in tools, or well-known libraries. For `Int128`/`Int256` and `UInt128`/`UInt256`, which exceed most languages' native integer sizes, custom deserialization may be required.

### Bool[​](#bool "Direct link to Bool")

Boolean values are encoded as a single byte, and can be deserialized similarly to `UInt8`.

- `0` is `false`
- `1` is `true`

### Float32, Float64[​](#float32-float64 "Direct link to Float32, Float64")

**Little-endian** floating-point numbers encoded as 4 bytes for `Float32` and 8 bytes for `Float64`. Similarly to integers, most languages provide proper tools to deserialize these values.

### BFloat16[​](#bfloat16 "Direct link to BFloat16")

[BFloat16](https://clickhouse.com/docs/sql-reference/data-types/float#bfloat16) (Brain Floating Point) is a 16-bit floating point format with the range of Float32 and reduced precision, making it useful for machine learning workloads. The wire format is essentially the top 16 bits of a Float32 value. If your language doesn't support it natively, the easiest way to handle it is to read and write as UInt16, converting to and from Float32:

To convert BFloat16 to Float32 (pseudocode):

```
// Read 2 bytes as little-endian UInt16
// Left-shift by 16 bits to get Float32 bits
bfloat16Bits = readUInt16()
float32Bits = bfloat16Bits << 16
floatValue = reinterpretAsFloat32(float32Bits)
```

To convert Float32 to BFloat16 (pseudocode):

```
// Right-shift Float32 bits by 16 to truncate to BFloat16
float32Bits = reinterpretAsUInt32(floatValue)
bfloat16Bits = float32Bits >> 16
writeUInt16(bfloat16Bits)
```

Sample underlying values for `BFloat16`:

```
SELECT CAST(1.25, 'BFloat16')
```

```
0xA0, 0x3F, // 1.25 as BFloat16
```

### Decimal32, Decimal64, Decimal128, Decimal256[​](#decimal "Direct link to Decimal32, Decimal64, Decimal128, Decimal256")

Decimal types are represented as **little-endian** integers with respective bit width.

- `Decimal32` - 4 bytes, or `Int32`.
- `Decimal64` - 8 bytes, or `Int64`.
- `Decimal128` - 16 bytes, or `Int128`.
- `Decimal256` - 32 bytes, or `Int256`.

When deserializing a Decimal value, the whole and fractional parts can be derived using the following pseudocode:

```
let scale_multiplier = 10 ** scale
let whole_part = trunc(value / scale_multiplier)  // truncate toward zero
let fractional_part = value % scale_multiplier
let result = Decimal(whole_part, fractional_part)
```

Where `trunc` performs truncation toward zero (not floor division, which differs for negative values), and `scale` is the number of digits after the decimal point. For example, for `Decimal(10, 2)` (an equivalent to `Decimal32(2)`), the scale is `2`, and the value `12345` will be represented as `(123, 45)`.

Serialization requires the reverse operation:

```
let scale_multiplier = 10 ** scale
let result = whole_part * scale_multiplier + fractional_part
```

See more details in the [Decimal types ClickHouse docs](https://clickhouse.com/docs/sql-reference/data-types/decimal).

### String[​](#string "Direct link to String")

ClickHouse strings are **arbitrary byte sequences**. They are not required to be valid UTF-8. The length prefix is the **byte length**, not the character count.

Encoded in two parts:

1. A variable-length integer (LEB128) that indicates the length of the string in bytes.
2. The raw bytes of the string.

For example, a string `foobar` will be encoded using *seven* bytes as follows:

```
0x06, // LEB128 length of the string (6)
0x66, // 'f'
0x6f, // 'o'
0x6f, // 'o'
0x62, // 'b'
0x61, // 'a'
0x72, // 'r'
```

### FixedString[​](#fixedstring "Direct link to FixedString")

Unlike `String`, `FixedString` has a fixed length, which is defined in the schema. It is encoded as a sequence of bytes, padded with trailing zero bytes if the value is shorter than `N`.

Note

When reading a `FixedString`, trailing zero bytes may be either padding or actual `\0` characters in the data, they are indistinguishable on the wire. ClickHouse itself preserves all `N` bytes as-is.

An empty `FixedString(3)` contains only padding zeroes:

```
0x00, 0x00, 0x00
```

Non-empty `FixedString(3)` containing the string `hi`:

```
0x68, // 'h'
0x69, // 'i'
0x00, // padding zero
```

Non-empty `FixedString(3)` containing the string `bar`:

```
0x62, // 'b'
0x61, // 'a'
0x72, // 'r'
```

No padding is required in the last example, since all *three* bytes are used.

### Date[​](#date "Direct link to Date")

Stored as `UInt16` (two bytes) representing the number of days ***since*** `1970-01-01`.

Supported range of values: `[1970-01-01, 2149-06-06]`.

Sample underlying values for `Date`:

```
SELECT CAST('2024-01-15', 'Date') AS d
```

```
0x19, 0x4D, // 19737 as UInt16 (little-endian) = 19737 days since 1970-01-01
```

### Date32[​](#date32 "Direct link to Date32")

Stored as `Int32` (four bytes) representing the number of days ***before or after*** `1970-01-01`.

Supported range of values: `[1900-01-01, 2299-12-31]`.

Sample underlying values for `Date32`:

```
SELECT CAST('2024-01-15', 'Date32') AS d
```

```
0x19, 0x4D, 0x00, 0x00, // 19737 as Int32 (little-endian) = 19737 days since 1970-01-01
```

A date before the epoch:

```
SELECT CAST('1900-01-01', 'Date32') AS d
```

```
0x21, 0x9C, 0xFF, 0xFF, // -25567 as Int32 (little-endian) = 25567 days before 1970-01-01
```

### DateTime[​](#datetime "Direct link to DateTime")

Stored as `UInt32` (four bytes) representing the number of seconds ***since*** `1970-01-01 00:00:00 UTC`.

Syntax:

```
DateTime([timezone])
```

For example, `DateTime` or `DateTime('UTC')`.

Note

The binary value is always a UTC epoch offset. The timezone does not change the encoding. However, the timezone **does** affect how string values are interpreted on insertion: inserting `'2024-01-15 10:30:00'` into a `DateTime('America/New_York')` column stores a different epoch value than inserting the same string into a `DateTime('UTC')` column, because the string is interpreted as local time in the column's timezone. On the wire, both are just `UInt32` epoch seconds.