如何计算文本的真实SHA1?

Pet*_*uss 6 postgresql digest

正如我的上一个问题(请参阅此处的详细信息),我正在使用

SELECT encode(digest(x::text::bytea, 'sha1'), 'hex') FROM xtmp;
Run Code Online (Sandbox Code Playgroud)

未解决,与原始哈希值不同...也许是带有符号::text的强制内部表示\n,因此解决方案将直接转换为bytea,但这是无效的转换。

其他解决方法也不是解决方案,

SELECT encode(digest( replace(x::text,'\n',E'\n')::bytea, 'sha1' ), 'hex') 
FROM xtmp
Run Code Online (Sandbox Code Playgroud)

...我尝试CREATE TABLE btmp (x bytea)COPY btmp FROM '/tmp/test.xml' ( FORMAT binary )但出现错误(“未知的复制文件签名”)。

Pet*_*uss 5

简单的解决方案!添加“\n”。

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

但真正的问题是获取原始文件而不剪切最后一个“\n”(最后一个 EOL)...让我们看看我的旧测试套件中的功能:

 INSERT INTO  xtmp (x) 
  SELECT array_to_string(array_agg(x),E'\n')::xml FROM ttmp
;
Run Code Online (Sandbox Code Playgroud)

这就是“错误”(在解决方法之后,COPY不会将完整文件加载到一行一个字段中)。
没有 array_to_string()添加最后一个 EOL,因此通过|| E'\n'修复 bug 来连接。


笔记

检查其他假设并为测试套件提供良好的解决方案。

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
Run Code Online (Sandbox Code Playgroud)

结果

062c3db8ce3458fc3ccaf2f930bf663d8ce31d7d  original1.xml
a05d91cbf0902b0fe341c979e9fc18fc69813f55  original2.xml
(stdin)= 062c3db8ce3458fc3ccaf2f930bf663d8ce31d7d
(stdin)= a05d91cbf0902b0fe341c979e9fc18fc69813f55
Run Code Online (Sandbox Code Playgroud)

所以sha1sum不使用额外的 EOL,字符串和文件就是一些。

现在在 SQL 上,同样的结论:

SELECT encode(digest('<root/>'::bytea, 'sha1'), 'hex') ;
SELECT encode(digest(E'<root/>\n'::bytea, 'sha1'), 'hex') ;
Run Code Online (Sandbox Code Playgroud)

结果

 062c3db8ce3458fc3ccaf2f930bf663d8ce31d7d
 a05d91cbf0902b0fe341c979e9fc18fc69813f55
Run Code Online (Sandbox Code Playgroud)

更好的测试套件的解决方案

对于这个简单的加载/保存文本过程来说,该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') ;
Run Code Online (Sandbox Code Playgroud)

结果

062c3db8ce3458fc3ccaf2f930bf663d8ce31d7d
a05d91cbf0902b0fe341c979e9fc18fc69813f55
Run Code Online (Sandbox Code Playgroud)

完美(!),现在没有 EOL 问题。