I have 7 8-bit integer values per record that I want to store in Postgres. Pg doesn\'t offer a single byte integer type, SMALLINT, or 2 bytes, being the smallest integer datatyp
"char"
This is a one-byte type in PostgreSQL that fits in the range of -128,127. From the docs,
The type
"char"
(note the quotes) is different fromchar(1)
in that it only uses one byte of storage. It is internally used in the system catalogs as a simplistic enumeration type.
You can bias this towards [-128,127], by subtracting 128 from any input in the range of [0-255] before you write to the database, and adding it back on the output when you read from the database.
-- works
SELECT (-128)::"char", 127::"char";
-- generates out of range
SELECT (-128)::"char";
SELECT 128::"char";
-- Shifts to unsigned range.
-- If you're going to be using "char"
-- review the results of this query!
SELECT
x::int AS "inputUnsigned",
chr(x) AS "extendedASCII",
-- this is the "char" types representation for that input.
signed::"char" AS "charRepresentation",
signed AS "inputUnsignedToSigned",
signed+128 AS "inputUnsignedToSignedToUnsigned"
FROM generate_series(1,255) AS gs(x)
-- Here we map the input in the range of [0,255] to [-128,127]
CROSS JOIN LATERAL ( VALUES (x::int-128) )
AS v(signed);
Small excerpt of the output
inputUnsigned | extendedASCII | charRepresentation | inputUnsignedToSigned | inputUnsignedToSignedToUnsigned
---------------+---------------+--------------------+-----------------------+---------------------------------
....
190 | ¾ | > | 62 | 190
191 | ¿ | ? | 63 | 191
192 | À | @ | 64 | 192
193 | Á | A | 65 | 193
194 | Â | B | 66 | 194
195 | Ã | C | 67 | 195
196 | Ä | D | 68 | 196
...
We use generate_series(1,255)
only because chr(0)
throws because you can't generate or output the ASCII NUL
(PostgreSQL uses cstrings)
pguint
ExtensionPguint is an extension that provides two one byte representations,
int1
(signed)uint1
(unsigned)