如何使用 pg_read_file 和 missing_ok=true 读取完整文件?

How to read full file with pg_read_file and missing_ok=true?

pg_read_file() 的以下所有用法都运行 没问题:

select pg_read_file('myFile.txt'); -- ok full file
select pg_read_file('myFile-notExists',0,10,true); -- NULL is Ok! 

但这些都是有问题的:

select pg_read_file('myFile-notExists.txt'); -- ERROR... It is not what I need
select pg_read_file('myFile.txt',0,10,true); -- ok not null, but need full file!

...我尝试用换行函数解决问题:

CREATE or replace FUNCTION pg_read_file(f text, missing_ok boolean) RETURNS text AS $$
  SELECT pg_read_file(f,0,922337203,missing_ok) 
   -- the max 9223372036854775807 is  too large, also 9223372036854775800, ....
$$ LANGUAGE SQL IMMUTABLE;

但它说 “错误:请求的长度太大” 用于最大长度测试...所以我使用了随机常数。 问题 1:“最大文件大小”值是多少?

select pg_read_file('myFile-notExists.txt',true); -- Ok! NULL is what I need
select pg_read_file('myFile.txt',true); -- Ok! full file.

问题2:请问还有其他方法可以解决这个问题吗?

在标准的 PostgreSQL v12 \df pg_read_file 中说:

   Schema   |     Name     | Result data type |      Argument data types      | Type
------------+--------------+------------------+-------------------------------+------
 pg_catalog | pg_read_file | text             | text                          | func
 pg_catalog | pg_read_file | text             | text, bigint, bigint          | func
 pg_catalog | pg_read_file | text             | text, bigint, bigint, boolean | func

为什么pg_read_file(text,boolean)不在pg_catalog中?会和其他模块或扩展产生一些不一致吗?

使用 pg_stat_file 来测试它的存在怎么样?

CREATE or replace FUNCTION pg_read_file(f text, missing_ok boolean) RETURNS text AS $$
  SELECT case 
     when pg_stat_file(f,missing_ok) is NULL then NULL 
     else pg_read_file(f) end
$$ LANGUAGE SQL IMMUTABLE;

这里存在竞争条件,文件可能在 pg_stat_file 之后但在 pg_read_file 之前消失,导致错误而不是 NULL return。

这是一个 Wiki,请编辑以增强此答案!

PS: 也检查 this discussion, performance questions and this alternative.


这是一个 pg_read_file() 错误...对于解决方法,没有真正好的解决方案 没有竞争条件( @jjanes 之前记得)。 Real-time 申请需要谨慎。

这里换一种方法,检索pg_stat_file的信息,避免丢失CPU。

这是一个品味问题,我认为 RECORD 很难用,我更喜欢 JSONb。

想象一下您正在使用 JSONb 的场景,例如使用 PostgREST...

构建 back-end

重用pg_stat_file

CREATE or replace FUNCTION jsonb_read_stat_file(
  f text,
  missing_ok boolean DEFAULT false
) RETURNS JSONb AS $f$
  SELECT j || jsonb_build_object( 'file',f,  'content',pg_read_file(f) )
  FROM to_jsonb( pg_stat_file(f,missing_ok) ) t(j)
  WHERE j IS NOT NULL
$f$ LANGUAGE SQL IMMUTABLE;

要仅获取内容,模拟纯 read_file(x,true),您可以使用 jsonb_read_stat_file('/tmp/text.txt',true)->>'content'


使用示例:

echo "Hello world!" > /tmp/text.txt
psql mydb -c "SELECT jsonb_read_stat_file('/tmp/text-ERROR.txt',true) IS NULL" # true
psql mydb -c "SELECT jsonb_read_stat_file('/tmp/text.txt',true)"
 {
   "file": "/tmp/text.txt", 
   "size": 13, 
   "isdir": false, 
   "access": "2020-08-09T14:44:28+00:00",
   "change": "2020-08-09T14:44:28+00:00", 
   "content": "Hello world!\n", 
   "creation": null, 
   "modification": "2020-08-09T14:44:28+00:00"
}