From 250279b86de5e56d02afba2f004717d42790cc6b Mon Sep 17 00:00:00 2001 From: Aleksander Alekseev Date: Thu, 18 Jul 2024 12:59:40 +0300 Subject: [PATCH v4] Add crc32(bytea) & crc32c(bytea) Per user requests. Aleksander Alekseev, reviewed by Nathan Bossart Discussion: https://postgr.es/m/CAJ7c6TNMTGnqnG=yXXUQh9E88JDckmR45H2Q+=ucaCLMOW1QQw@mail.gmail.com --- doc/src/sgml/func.sgml | 34 ++++++++++++++ src/backend/utils/hash/pg_crc.c | 56 ++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 8 ++++ src/test/regress/expected/opr_sanity.out | 2 + src/test/regress/expected/strings.out | 27 ++++++++++++ src/test/regress/sql/strings.sql | 9 ++++ 6 files changed, 136 insertions(+) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 0f7154b76a..a0541d897f 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -4490,6 +4490,40 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); + + + + crc32 + + crc32 ( bytea ) + text + + + Computes the CRC32 value of the binary string. + + + crc32('PostgreSQL'::bytea) + cb97b83b + + + + + + + crc32c + + crc32c ( bytea ) + text + + + Computes the CRC32C value of the binary string. + + + crc32c('PostgreSQL'::bytea) + a7c16abd + + + diff --git a/src/backend/utils/hash/pg_crc.c b/src/backend/utils/hash/pg_crc.c index 3595938dc4..6965a7f8d5 100644 --- a/src/backend/utils/hash/pg_crc.c +++ b/src/backend/utils/hash/pg_crc.c @@ -18,8 +18,12 @@ */ #include "c.h" +#include "postgres.h" +#include "port/pg_crc32c.h" +#include "utils/builtins.h" #include "utils/pg_crc.h" +#include "varatt.h" /* * Lookup table for calculating CRC-32 using Sarwate's algorithm. @@ -95,3 +99,55 @@ const uint32 pg_crc32_table[256] = { 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; + +/* + * Calculate CRC32 of a bytea value and return it as text. + */ +Datum +crc32_bytea(PG_FUNCTION_ARGS) +{ + bytea *in = PG_GETARG_BYTEA_PP(0); + size_t len; + pg_crc32 crc; + char result[16]; + + /* calculate the length of the buffer using varlena metadata */ + len = VARSIZE_ANY_EXHDR(in); + + /* get the crc value */ + INIT_TRADITIONAL_CRC32(crc); + COMP_TRADITIONAL_CRC32(crc, VARDATA_ANY(in), len); + FIN_TRADITIONAL_CRC32(crc); + + /* format the hex string */ + snprintf(result, sizeof(result), "%08x", (uint32)crc); + + /* convert to text and return it */ + PG_RETURN_TEXT_P(cstring_to_text(result)); +} + +/* + * Calculate CRC32C of a bytea value and return it as text. + */ +Datum +crc32c_bytea(PG_FUNCTION_ARGS) +{ + bytea *in = PG_GETARG_BYTEA_PP(0); + size_t len; + pg_crc32c crc; + char result[16]; + + /* calculate the length of the buffer using varlena metadata */ + len = VARSIZE_ANY_EXHDR(in); + + /* get the crc value */ + INIT_CRC32C(crc); + COMP_CRC32C(crc, VARDATA_ANY(in), len); + FIN_CRC32C(crc); + + /* format the hex string */ + snprintf(result, sizeof(result), "%08x", (uint32)crc); + + /* convert to text and return it */ + PG_RETURN_TEXT_P(cstring_to_text(result)); +} diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index d36f6001bb..c31b1c72ec 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -7743,6 +7743,14 @@ proname => 'system', provolatile => 'v', prorettype => 'tsm_handler', proargtypes => 'internal', prosrc => 'tsm_system_handler' }, +# non-cryptographic +{ oid => '8571', descr => 'CRC32 value', + proname => 'crc32', proleakproof => 't', prorettype => 'text', + proargtypes => 'bytea', prosrc => 'crc32_bytea' }, +{ oid => '8572', descr => 'CRC32C value', + proname => 'crc32c', proleakproof => 't', prorettype => 'text', + proargtypes => 'bytea', prosrc => 'crc32c_bytea' }, + # cryptographic { oid => '2311', descr => 'MD5 hash', proname => 'md5', proleakproof => 't', prorettype => 'text', diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 9d047b21b8..0d734169f1 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -874,6 +874,8 @@ xid8ne(xid8,xid8) xid8cmp(xid8,xid8) uuid_extract_timestamp(uuid) uuid_extract_version(uuid) +crc32(bytea) +crc32c(bytea) -- restore normal output mode \a\t -- List of functions used by libpq's fe-lobj.c diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index 52b69a107f..c795df3056 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -2255,6 +2255,33 @@ SELECT sha512('The quick brown fox jumps over the lazy dog.'); \x91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed (1 row) +-- +-- CRC32 +-- +SELECT crc32(''::bytea); + crc32 +---------- + 00000000 +(1 row) + +SELECT crc32('The quick brown fox jumps over the lazy dog.'::bytea); + crc32 +---------- + 519025e9 +(1 row) + +SELECT crc32c(''::bytea); + crc32c +---------- + 00000000 +(1 row) + +SELECT crc32c('The quick brown fox jumps over the lazy dog.'::bytea); + crc32c +---------- + 190097b3 +(1 row) + -- -- encode/decode -- diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql index 3959678992..f8cd621d9a 100644 --- a/src/test/regress/sql/strings.sql +++ b/src/test/regress/sql/strings.sql @@ -719,6 +719,15 @@ SELECT sha384('The quick brown fox jumps over the lazy dog.'); SELECT sha512(''); SELECT sha512('The quick brown fox jumps over the lazy dog.'); +-- +-- CRC32 +-- +SELECT crc32(''::bytea); +SELECT crc32('The quick brown fox jumps over the lazy dog.'::bytea); + +SELECT crc32c(''::bytea); +SELECT crc32c('The quick brown fox jumps over the lazy dog.'::bytea); + -- -- encode/decode -- -- 2.45.2