Как рассчитать настоящий SHA1 текста?

Как и в моем последнем вопросе (подробнее см. там), я использую

SELECT encode(digest(x::text::bytea, 'sha1'), 'hex') FROM xtmp;

Не решен, это не тот же хеш, что и исходный... Возможно, ::text принудительно использует внутреннее представление с \n символами, поэтому решение будет напрямую приведено к bytea, но это недопустимое приведение.

Другой обходной путь также не является решением,

SELECT encode(digest( replace(x::text,'\n',E'\n')::bytea, 'sha1' ), 'hex') 
FROM xtmp

... Пробую CREATE TABLE btmp (x bytea) и COPY btmp FROM '/tmp/test.xml' ( FORMAT binary ), но ошибка ("неизвестная подпись файла COPY").


person Peter Krauss    schedule 26.01.2018    source источник


Ответы (1)


Простое решение! Добавьте "\n".

SELECT encode(digest((x::text||E'\n')::bytea, 'sha1'), 'hex') FROM xtmp;

Но реальная проблема заключается в том, чтобы получить исходный файл без вырезания последнего "\n" (последний EOL)... Давайте посмотрим на функцию в my старый тестовый набор:

 INSERT INTO  xtmp (x) 
  SELECT array_to_string(array_agg(x),E'\n')::xml FROM ttmp
;

Именно здесь "ошибка" (после обхода COPY, который не загружает полный файл в одну строку одного поля).
array_to_string() не добавляет последний EOL, поэтому объединение с помощью || E'\n' устранило ошибку.


ЗАМЕТКИ

Проверка другой гипотезы и предложение хорошего решения для тестового набора.

Правило POSIX не проблема...

Конец строки (EOL) является обязательным для файловых систем POSIX (и недвоичного режима), см. этот ответ о EOL. Мы можем представить что-то вроде «представления строк и файлов различаются на EOL»… Мы можем проверить? отличается?

С помощью терминала мы можем продемонстрировать, что нет проблемы "строка vs файл", нет странной зависимости от EOL:

printf "<root/>" > original1.xml 
printf "<root/>\n" > original2.xml 
sha1sum original*.xml
printf "<root/>" | openssl sha1
printf "<root/>\n" | openssl sha1

полученные результаты

062c3db8ce3458fc3ccaf2f930bf663d8ce31d7d  original1.xml
a05d91cbf0902b0fe341c979e9fc18fc69813f55  original2.xml
(stdin)= 062c3db8ce3458fc3ccaf2f930bf663d8ce31d7d
(stdin)= a05d91cbf0902b0fe341c979e9fc18fc69813f55

Таким образом, sha1sum не использует дополнительный EOL, строка и файл - это некоторые.

Теперь по SQL те же выводы:

SELECT encode(digest('<root/>'::bytea, 'sha1'), 'hex') ;
SELECT encode(digest(E'<root/>\n'::bytea, 'sha1'), 'hex') ;

полученные результаты

 062c3db8ce3458fc3ccaf2f930bf663d8ce31d7d
 a05d91cbf0902b0fe341c979e9fc18fc69813f55

Решение для лучшего тестового набора

Команда COPY неудобна для этой простой процедуры загрузить/сохранить текст, давайте вместо этого воспользуемся прямой функцией getfile:

CREATE FUNCTION getfile(p_file text) RETURNS text AS $$
   with open(args[0],"r") as content_file:
       content = content_file.read()
   return content
$$ LANGUAGE PLpythonU;

SELECT encode(digest( getfile('/tmp/original1.xml') ::bytea, 'sha1'), 'hex') ;
SELECT encode(digest( getfile('/tmp/original2.xml') ::bytea, 'sha1'), 'hex') ;

полученные результаты

062c3db8ce3458fc3ccaf2f930bf663d8ce31d7d
a05d91cbf0902b0fe341c979e9fc18fc69813f55

Отлично (!), теперь нет проблем с EOL.

person Community    schedule 28.01.2018