Skip to content

Bytea gzip sample

This sample ports pgrx’s bytea example. It compresses arbitrary bytes with gzip, returns the first gzip member’s bytes with gunzip, and decodes its payload as strict UTF-8 with gunzip_as_text.

CREATE EXTENSION ankus_bytea;
SELECT gunzip_as_text(gzip('hi there'));
-- hi there
SELECT gunzip(gzip('hi there'::bytea));
-- \x6869207468657265
SELECT gunzip_as_text(gzip(convert_to('中文 € 😀', 'UTF8')));
-- 中文 € 😀

The untyped 'hi there' literal resolves to the function’s bytea argument. An existing text or varchar value needs an explicit conversion such as convert_to(value, 'UTF8'). PostgreSQL does not implicitly convert those typed arguments when resolving this function.

SQL NULL arguments return SQL NULL. Present empty bytes produce a complete gzip member; decoding that member returns present empty bytea or empty text.

gunzip preserves pgrx’s libflate decoder behavior: it consumes only the first member, requires all eight trailer bytes, and verifies the data checksum. Later members and trailing content are separate inputs. Like that decoder, it reads but does not compare the trailer’s ISIZE field and does not independently reject unused header flags. A header checksum (FHCRC) is checked against the header as libflate re-encodes it, so unknown flag bits and unusual XFL values are ignored. These functions are a sample codec, not an archive validator.

The sample owns gzip framing around .NET’s standard raw DEFLATE codec. This preserves empty members and the first-member boundary.

Malformed gzip data raises InvalidDataException. Invalid UTF-8 raises DecoderFallbackException rather than inserting replacement characters; binary gunzip still returns those bytes exactly. Ankus reports these ordinary .NET exceptions as SQLSTATE 38000. pgrx’s expect failures panic and report XX000. After an error, roll back the failed transaction or savepoint before issuing another query.