简体   繁体   English

使用不带 pg_read_file 的 PostgreSQL 读取二进制文件

[英]Read binary file with PostgreSQL without pg_read_file

I need a solution to the following problem with a clear PostgreSQL 9.4:我需要一个明确的 PostgreSQL 9.4 来解决以下问题:

  • Read a zipped file from server into a bytea column将压缩文件从服务器读取到 bytea 列
  • No extensions allowed不允许扩展
  • Superuser allowed允许超级用户
  • Postgres user has permission to read the file Postgres 用户有权读取文件
  • Can be a user function可以是用户function

EDIT:编辑:

The file is outside cluster path, so normal functions raise:该文件位于集群路径之外,因此正常功能会引发:
SQL Error: ERROR: absolute path not allowed SQL 错误:错误:不允许绝对路径

Here is a simple function get_file_contents(filename text) returns bytea for the job.这是一个简单的 function get_file_contents(filename text) returns bytea

create or replace function get_file_contents(filename text) returns bytea as
$fn$
 declare 
    lo_oid oid;
    retval bytea;
 begin
    lo_oid := lo_import(filename);
    retval := lo_get(lo_oid);
    perform lo_unlink(lo_oid);
    return retval;
 end;
$fn$ language plpgsql;
  • Trivial usage琐碎的用法
-- Read the great work of Sun Tzu
select get_file_contents('/media/data/ForeignData/The Art Of War.pdf');

-- Insert into a table, update a table
insert into mytable (mycolumn[,<others>]) values (get_file_contents(myfilename)[,<others>]);
update mytable set mycolumn = get_file_contents(myfilename) where <whatever there>;

After a lot o research, I came out with the following function:经过大量研究,我得出以下 function:

  CREATE OR REPLACE FUNCTION file_read(file text)  
  RETURNS bytea AS $$
    DECLARE
      content text;
      tmp text;
    BEGIN
      file := quote_literal(file);
      tmp := quote_ident(md5(random()::text));

      -- create tmp table using random name
      EXECUTE 'CREATE TEMP TABLE ' || tmp || ' (id oid, file_name text, content bytea)';
      
      -- add given filename
      EXECUTE 'INSERT INTO '|| tmp ||' (file_name) VALUES('|| file ||')';
            
      -- add the document to large object storage and return the link id
      BEGIN
           EXECUTE 'UPDATE ' || tmp || ' SET id = lo_import(file_name) ';
      EXCEPTION WHEN OTHERS THEN
           RETURN NULL;
      END;
            
      -- pull document from large object storage
      EXECUTE 'UPDATE ' || tmp || ' SET content = lo_get(id) ';
      
      -- delete the file from large object storage
      EXECUTE 'SELECT lo_unlink(id) FROM ' || tmp;
      
      -- save data to content variable
      EXECUTE 'SELECT content FROM ' || tmp INTO content;
      
      -- drop tmp table      
      EXECUTE 'DROP TABLE ' || tmp;

      -- return 
      RETURN content;
    END;
  $$ LANGUAGE plpgsql VOLATILE;

Sample use case:示例用例:

Read from file从文件中读取
select file_read(concat('/tmp/', '28528026bc302546d17ce7e82400ab7e.zip')

Update column更新栏
update custom_table set content = file_read(filename)

Use the built-in function pg_read_binary_file() .使用内置的 function pg_read_binary_file() It's available since Postgres 9.1 and does exactly what you want.它从 Postgres 9.1 开始可用,并且完全符合您的要求。 The manual: 手册:

Returns all or part of a file.返回文件的全部或部分。 This function is identical to pg_read_file except that it can read arbitrary binary data, returning the result as bytea not text ;这个 function 与pg_read_file相同,只是它可以读取任意二进制数据,返回结果为bytea而不是text accordingly, no encoding checks are performed.因此,不执行编码检查。

This function is restricted to superusers by default, but other users can be granted EXECUTE to run the function.默认情况下,此 function 仅限于超级用户,但其他用户可以被授予EXECUTE以运行 function。

So to...所以要...

Read a zipped file from server into a bytea column将压缩文件从服务器读取到bytea

UPDATE custom_table
SET    content = pg_read_binary_file('/tmp/28528026bc302546d17ce7e82400ab7e.zip')
WHERE  id = 123;

Considerably faster than any workaround.比任何解决方法都要快得多。

Note this restriction, quoting the manual :请注意此限制,引用手册

Only files within the database cluster directory and the log_directory can be accessed.只能访问数据库集群目录和 log_directory 中的文件。 Use a relative path for files in the cluster directory, and a path matching the log_directory configuration setting for log files.对集群目录中的文件使用相对路径,并为日志文件使用与 log_directory 配置设置匹配的路径。

You can overcome the path restriction with a symlink from your db directory to any other directory.您可以使用从 db 目录到任何其他目录的符号链接来克服路径限制。 Be wary of possible security implications, though.不过要警惕可能的安全隐患。 See:看:

Also, consider upgrading to a current version of Postgres Postgres 9.4 has reached EOL on February 13, 2020 .此外,请考虑升级到 Postgres 的当前版本Postgres 9.4 已于 2020 年 2 月 13 日达到 EOL

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在桌面 PostgreSQL 中使用 pg_read_file 读取文件 - using pg_read_file read file in desktop PostgreSQL pg_read_file没有这样的文件或目录错误? - Pg_read_file no such file or directory error? 没有pg_read_file的情况下如何将XML本地文件加载到postgres? - How can I load an XML local file to postgres without pg_read_file? 如何使用 pg_read_file 和 missing_ok=true 读取完整文件? - How to read full file with pg_read_file and missing_ok=true? 使用pg_read_binary_file导入PostgreSQL 9.5 - import in postgresql 9.5 with pg_read_binary_file PostgreSQL 14.5 pg_read_binary_file 无法打开文件进行读取:参数无效 - PostgreSQL 14.5 pg_read_binary_file could not open file for reading: Invalid argument PostgreSQL 9.x-pg_read_binary_file并将文件插入bytea - PostgreSQL 9.x - pg_read_binary_file & inserting files into bytea 如何授予非超级用户特权以执行函数pg_read_binary_file? - How to GRANT priveleges to non-superuser to execute function pg_read_binary_file? 如何阅读PostgreSQL wal文件数据? 是否有任何命令将PostgreSQL二进制文件转换为可读文本格式? - How to read PostgreSQL wal file data? Is there is any command to convert PostgreSQL binary to readable text format? 读取文件并使用postgresql plperl打印 - Read file and print with postgresql plperl
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM