md5 () работает с литералом, но не с данными столбца

при проверке в PostgreSQL md5() функции я заметил очень странное поведение:

работает

SELECT md5('abc')
--"900150983cd24fb0d6963f7d28e17f72"

но использование функции md5 () в запросе:

SELECT request_id, md5(request_id)
FROM Request
ORDER BY request_id

приводит к этой ошибке:

ERROR:  function md5(integer) does not exist
LINE 1: SELECT request_id, md5(request_id)
                           ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

********** Error **********

ERROR: function md5(integer) does not exist
SQL state: 42883
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Character: 20

как функция не exist, если он работал в первом запросе? что я делаю неправильно; Как правильно использовать md5() в SELECT запрос?

4 ответов


функция ожидает в качестве параметра текст. Брось его:

SELECT request_id, md5(request_id::text)
FROM Request
ORDER BY request_id

функция с именем md5, принимающая целочисленный параметр, не существует, но вы можете ее создать:

create function md5(integer)
returns text as $$

select md5(::text);

$$ language sql immutable;

тогда будет 3 подписи для md5:

=> \df md5
                          List of functions
   Schema   | Name | Result data type | Argument data types |  Type  
------------+------+------------------+---------------------+--------
 pg_catalog | md5  | text             | bytea               | normal
 pg_catalog | md5  | text             | text                | normal
 public     | md5  | text             | integer             | normal

как указано в комментариях к этому ответу, хэш md5 текстового представления целого числа может быть не тем, что вы хотите. Чтобы иметь хэш двоичного файла, подпись md5 принимает bytea параметр должен быть используется:

select md5(('\x' || right('0000000' || to_hex(200), 8))::bytea);
               md5                
----------------------------------
 b7b436d004c1cc0501bee9e296d2eaa4

и заменить ранее созданную функцию:

create or replace function md5(integer)
returns text as $$

select md5(('\x' || right('0000000' || to_hex(), 8))::bytea);

$$ language sql immutable;

В общем случае не имеет смысла брать md5 целого числа. Кажется вероятным, что вы пытаетесь скрыть последовательность, чтобы она казалась полуслучайной в порядке. Если это так, есть гораздо лучший способ:

использовать pseudo_encrypt функция, перечисленная в вики PostgreSQL. Это намного разумнее, чем пытаться взять md5 целого числа, а затем (предположительно) усечь его.

выше не обеспечьте сильную криптографическую случайность, но ни ваш подход. Если вам нужно, чтобы ваши идентификаторы запроса были действительно непредсказуемыми по соображениям безопасности, а не просто неочевидными с первого взгляда, вы должны использовать сильный криптографический генератор случайных чисел и быть готовы справиться с дубликатами с помощью временных окон и т. д.


ошибка немного вводит в заблуждение;md5() функция существует, просто не для работы над чисел. Используйте встроенный CAST() функция для преобразования целочисленного поля в текст, и она будет работать:

SELECT request_id, md5(CAST(request_id AS TEXT))
FROM Request
ORDER BY request_id

--1;"c4ca4238a0b923820dcc509a6f75849b"
--2;"c81e728d9d4c2f636f067f89cc14862c"
--etc

Я просто пытаюсь создать неочевидное, неповторяющееся значение, которое может использоваться для поиска записи.

вам нужен биективный хэш. Я использую CRC функция CPU в пользовательской функции C. Для процессоров, которые не имеют функции, можно использовать таблицу подстановки.

этот подход гарантированно даст вам уникальное "случайное" число для каждого уникального 32-битного ввода.

Если вы знаете, как генерировать функции C (не trivial), будет простой задачей найти, как использовать CRC.