KDB knowledge

Bytes, hex and base64

Store raw bytes (hashes, keys, small images) and turn them into hex or base64 text and back.

A BYTES value holds raw bytes: any byte from 0 to 255, also zero bytes. Good uses are a file hash (SHA-256 is 32 bytes), a key, a signature or a very small image. BYTEA and BLOB are other names for the same column type (see column types). One value can be at most 16 MB; keep big files outside the database and save their path and hash.

Setup used by the examples below:

CREATE TABLE reports (
  id LONG PRIMARY KEY AUTO,
  symbol STRING NOT NULL,
  fiscal_year STRING NOT NULL,
  pdf_url STRING,
  pdf_sha256 BYTES
);
INSERT INTO reports (symbol, fiscal_year, pdf_url, pdf_sha256) VALUES
  ('CITY', '2082/83', 'https://files.example.com/city/2082-83-q4.pdf',
   X'9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08'),
  ('VOLT', '2082/83', 'https://files.example.com/volt/2082-83-q4.pdf', NULL);

Example: A report PDF stays outside; KDB keeps its SHA-256 hash

SELECT symbol,
       pdf_sha256,
       length(pdf_sha256) AS bytes,
       hex(pdf_sha256) AS hash_hex,
       to_base64(pdf_sha256) AS hash_base64
FROM reports
ORDER BY symbol;

Result:

symbol (STRING)pdf_sha256 (BYTES)bytes (LONG)hash_hex (STRING)hash_base64 (STRING)
CITY\x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08329f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=
VOLTNULLNULLNULLNULL

(2 rows)

X'...' bytes literal

Syntax:

X'0A0B'        x'0a0b'        X''
'\x0a0b'       text that becomes BYTES in a BYTES column or CAST
CAST('\x0a0b' AS BYTES)       '\x0a0b'::BYTES

X'...' writes bytes in hex inside SQL. Each byte is two hex digits; big or small letters both work. There must be no space between X and the quote.

When text goes into a BYTES column (or CAST(... AS BYTES)):

TextBytes
starts with \x, like '\x0a0b'the hex digits after \x
any other text, like 'hi'the UTF-8 bytes of the text (\x6869)

Example

SELECT X'0A0B' AS a,
       x'0a0b' AS small_letters,
       X'' AS empty,
       '\x0a0b'::BYTES AS from_hex_text,
       CAST('hi' AS BYTES) AS from_text,
       X'0102' || X'03' AS joined;

Result:

a (BYTES)small_letters (BYTES)empty (BYTES)from_hex_text (BYTES)from_text (BYTES)joined (BYTES)
\x0a0b\x0a0b\x\x0a0b\x6869\x010203

(1 row)

Example: Store and compare file hashes

Setup:

CREATE TABLE avatars (user_id LONG PRIMARY KEY, png_header BYTES, sha256 BYTES);
INSERT INTO avatars VALUES
  (1, X'89504E470D0A1A0A', '\x2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'),
  (2, 'not a png', NULL);
SELECT user_id, png_header, length(png_header) AS bytes,
       png_header = X'89504E470D0A1A0A' AS is_png
FROM avatars
ORDER BY user_id;

Result:

user_id (LONG)png_header (BYTES)bytes (LONG)is_png (BOOL)
1\x89504e470d0a1a0a8true
2\x6e6f74206120706e679false

(2 rows)

Example: Bytes compared with text

SELECT X'6869' = 'hi' AS same_as_text,
       X'0A0B' = '\x0a0b' AS same_as_hex_text,
       X'01' < X'02' AS smaller,
       length('\x0a0b') AS text_letters,
       length('\x0a0b'::BYTES) AS bytes;

Result:

same_as_text (BOOL)same_as_hex_text (BOOL)smaller (BOOL)text_letters (LONG)bytes (LONG)
truetruetrue62

(1 row)

Example: An odd number of hex digits (shows an error)

SELECT X'ABC';

Result:

Error: line 1, column 8: unhex: 'ABC' is not hex (an even number of the digits 0-9 and a-f)

Example: Bad hex in a BYTES column (shows an error)

INSERT INTO reports (symbol, fiscal_year, pdf_sha256) VALUES ('COAST', '2082/83', '\x9F86ZZ');

Result:

Error: column 'pdf_sha256' (BYTES): '\x9F86ZZ' is not hex bytes; write them like '\x0a0b' or X'0A0B'

hex

Syntax:

hex(value)

Writes bytes as hex text: two small-letter digits for every byte. Text is written as its UTF-8 bytes. A whole number is written as a hex number.

ArgumentTypeMeaning
valueBYTES, STRING or a whole numberwhat to write as hex

Example

SELECT hex(X'00FF10') AS from_bytes,
       hex('CITY') AS from_text,
       hex(255) AS from_number,
       hex(-1) AS negative,
       hex('न') AS nepali_letter;

Result:

from_bytes (STRING)from_text (STRING)from_number (STRING)negative (STRING)nepali_letter (STRING)
00ff1043495459ffffffffffffffffffe0a4a8

(1 row)

Example: Show a short hash code for each report on a web page

SELECT symbol, left(hex(pdf_sha256), 12) AS short_hash
FROM reports
WHERE pdf_sha256 IS NOT NULL;

Result:

symbol (STRING)short_hash (STRING)
CITY9f86d081884c

(1 row)

unhex

Syntax:

unhex(hex_text)

Reads hex text and gives the bytes. It is the opposite of hex.

ArgumentTypeMeaning
hex_textSTRINGan even number of hex digits (0-9, a-f or A-F), nothing else

Example

SELECT unhex('4E4142494C') AS a, unhex('00ff10') AS b, unhex('') AS empty;

Result:

a (BYTES)b (BYTES)empty (BYTES)
\x4e4142494c\x00ff10\x

(1 row)

Example: Save a SHA-256 hash as 32 bytes instead of 64 letters

Setup:

INSERT INTO reports (symbol, fiscal_year, pdf_url, pdf_sha256)
VALUES ('COAST', '2082/83', 'https://files.example.com/coast/2082-83-q4.pdf',
        unhex('2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae'));
SELECT symbol, length(pdf_sha256) AS bytes, hex(pdf_sha256) AS hash_hex
FROM reports
WHERE symbol = 'COAST';

Result:

symbol (STRING)bytes (LONG)hash_hex (STRING)
COAST322c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae

(1 row)

Example: Spaces are not allowed (shows an error)

SELECT unhex('4E 41 42');

Result:

Error: line 1, column 8: unhex: '4E 41 42' is not hex (an even number of the digits 0-9 and a-f)

to_base64

Syntax:

to_base64(value)

Writes bytes as base64 text (letters A-Z a-z 0-9 + /, with = at the end to fill). Text is written as its UTF-8 bytes.

ArgumentTypeMeaning
valueBYTES or STRINGwhat to write as base64

Example

SELECT to_base64(X'00FF10') AS bytes_value,
       to_base64('CITY') AS text_value,
       to_base64('नेपाल') AS nepali,
       to_base64('') AS empty;

Result:

bytes_value (STRING)text_value (STRING)nepali (STRING)empty (STRING)
AP8QQ0lUWQ==4KSo4KWH4KSq4KS+4KSy

(1 row)

Example: Send a small image to an app inside JSON

Setup:

CREATE TABLE avatars (user_id LONG PRIMARY KEY, image BYTES);
INSERT INTO avatars VALUES (7, X'89504E470D0A1A0A0000000D49484452');
SELECT json_object('user_id', user_id, 'image_base64', to_base64(image)) AS answer
FROM avatars;

Result:

answer (JSON)
{"user_id":7,"image_base64":"iVBORw0KGgoAAAANSUhEUg=="}

(1 row)

from_base64

Syntax:

from_base64(text)

Reads base64 text and gives the bytes. It is the opposite of to_base64.

ArgumentTypeMeaning
textSTRINGbase64 text

Example

SELECT from_base64('AP8Q') AS a,
       from_base64('TkFCSUw=') AS with_padding,
       from_base64('TkFCSUw') AS without_padding,
       from_base64('TkFC
SUw=') AS with_line_break;

Result:

a (BYTES)with_padding (BYTES)without_padding (BYTES)with_line_break (BYTES)
\x00ff10\x4e4142494c\x4e4142494c\x4e4142494c

(1 row)

Example: A mobile app uploads an avatar as base64

Setup:

CREATE TABLE avatars (user_id LONG PRIMARY KEY, image BYTES);
INSERT INTO avatars VALUES (7, from_base64('iVBORw0KGgoAAAANSUhEUg=='));
SELECT user_id, image, length(image) AS bytes FROM avatars;

Result:

INSERT INTO avatars VALUES (7, from_base64('iVBORw0KGgoAAAANSUhEUg=='))

1 row(s) inserted

SELECT user_id, image, length(image) AS bytes FROM avatars

user_id (LONG)image (BYTES)bytes (LONG)
7\x89504e470d0a1a0a0000000d4948445216

(1 row)

Example: Not base64 (shows an error)

SELECT from_base64('abc$');

Result:

Error: line 1, column 8: from_base64: the text is not valid base64

encode

Syntax:

encode(value, format)

Writes bytes as text in format: 'hex', 'base64' or 'escape', as PostgreSQL does. hex() and to_base64() do the same as the first two.

ArgumentTypeMeaning
valueBYTES or STRINGwhat to write (text is written as its UTF-8 bytes)
formatSTRING'hex', 'base64' or 'escape' (big or small letters)

Example

SELECT encode(X'00FF10', 'hex') AS hex_text,
       encode(X'00FF10', 'base64') AS base64_text,
       encode(X'00FF10', 'escape') AS escape_text,
       encode('CITY', 'HEX') AS text_as_hex;

Result:

hex_text (STRING)base64_text (STRING)escape_text (STRING)text_as_hex (STRING)
00ff10AP8Q\000\37743495459

(1 row)

Example: Other formats are an error (shows an error)

SELECT encode(X'00FF10', 'utf8');

Result:

Error: line 1, column 8: encode: format 'utf8' is not supported; use 'hex', 'base64' or 'escape'

decode

Syntax:

decode(text, format)

Reads text in format ('hex', 'base64' or 'escape') and gives the bytes. It is the opposite of encode, and does the same as unhex() and from_base64().

ArgumentTypeMeaning
textSTRINGhex, base64 or escape text
formatSTRING'hex', 'base64' or 'escape' (big or small letters)

Example

SELECT decode('00ff10', 'hex') AS from_hex,
       decode('AP8Q', 'base64') AS from_base64_text,
       decode('00ff10', 'hex') = decode('AP8Q', 'base64') AS same_bytes;

Result:

from_hex (BYTES)from_base64_text (BYTES)same_bytes (BOOL)
\x00ff10\x00ff10true

(1 row)

Example: Check a download: compare the hash the server sent with the saved one

SELECT symbol,
       pdf_sha256 = decode('n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=', 'base64') AS hash_matches
FROM reports
WHERE symbol = 'CITY';

Result:

symbol (STRING)hash_matches (BOOL)
CITYtrue

(1 row)

Example: Wrong format name (shows an error)

SELECT decode('hello', 'utf8');

Result:

Error: line 1, column 8: decode: format 'utf8' is not supported; use 'hex', 'base64' or 'escape'

convert_to

Syntax:

convert_to(text, encoding)

The bytes of a text in an encoding (PostgreSQL). convert_to(token, 'UTF8') is how PostgreSQL code turns a text into bytes before hashing it.

ArgumentTypeMeaning
textSTRINGthe text
encodingSTRING'UTF8' (also 'UTF-8'), 'LATIN1' or 'SQL_ASCII'

Example

SELECT convert_to('CITY', 'UTF8') AS utf8_bytes,
       convert_to('नेपाल', 'UTF8') AS nepali_bytes,
       convert_to('Æ', 'LATIN1') AS latin1_byte;

Result:

utf8_bytes (BYTES)nepali_bytes (BYTES)latin1_byte (BYTES)
\x43495459\xe0a4a8e0a587e0a4aae0a4bee0a4b2\xc6

(1 row)

Example: Not in LATIN1 (shows an error)

SELECT convert_to('नेपाल', 'LATIN1');

Result:

Error: line 1, column 8: convert_to: character 'न' has no equivalent in encoding "LATIN1"

convert_from

Syntax:

convert_from(bytes, encoding)

The text that bytes in an encoding stand for (PostgreSQL). The opposite of convert_to.

ArgumentTypeMeaning
bytesBYTESthe bytes
encodingSTRING'UTF8', 'LATIN1' or 'SQL_ASCII'

Example

SELECT convert_from('\x43495459'::bytea, 'UTF8') AS text,
       convert_from('\xc6'::bytea, 'LATIN1') AS latin1;

Result:

text (STRING)latin1 (STRING)
CITYÆ

(1 row)

Example: Not UTF-8 (shows an error)

SELECT convert_from('\xff'::bytea, 'UTF8');

Result:

Error: line 1, column 8: convert_from: invalid byte sequence for encoding "UTF8": 0xff