如何从Postgres内部列出文件夹中的文件?

Chr*_*ian 7 postgresql

有没有办法列出文件夹中的文件?

就像是:

select * from pg_ls_dir('/home/christian')
Run Code Online (Sandbox Code Playgroud)

我试过pg_ls_dir但是,根据文件:

只能log_directory 访问数据库集群目录中的文件.使用群集目录中文件的相对路径,以及与log_directory日志文件的配置设置匹配的路径.这些功能的使用仅限于超级用户.

我需要列出postgres目录之外的文件夹中的文件,类似于它的工作方式COPY.

Dav*_*vis 9

使用PostgreSQL 9.3,可以避免安装语言扩展的开销:

DROP TABLE IF EXISTS files;
CREATE TABLE files(filename text);
COPY files FROM PROGRAM 'find /usr/bin -maxdepth 1 -type f -printf "%f\n"'; 
SELECT * FROM files ORDER BY filename ASC;
Run Code Online (Sandbox Code Playgroud)

创建一个具有2000分+排在81毫秒我的机器上,从表[zip.

通常,该COPY命令需要超级用户权限.由于文件系统的路径是硬编码的(即,不是来自用户的未经过计算的值),因此首先使用超级用户帐户(例如postgres)定义函数不会造成很大的安全风险,如下所示:

CREATE OR REPLACE FUNCTION files()
  RETURNS SETOF text AS
$BODY$
BEGIN
  SET client_min_messages TO WARNING;
  DROP TABLE IF EXISTS files;
  CREATE TEMP TABLE files(filename text);
  COPY files FROM PROGRAM 'find /usr/bin -maxdepth 1 -type f -printf "%f\n"';
  RETURN QUERY SELECT * FROM files ORDER BY filename ASC;
END;
$BODY$
  LANGUAGE plpgsql SECURITY DEFINER;
Run Code Online (Sandbox Code Playgroud)

使用非超级用户帐户登录PostgreSQL,然后:

SELECT * FROM files();
Run Code Online (Sandbox Code Playgroud)

应返回相同的结果列表,不会出现任何安全违规错误.


SECURITY DEFINER告诉PostgreSQL的到被用来创建功能的帐户的作用下运行的功能.由于它是使用超级用户角色创建的,因此无论执行命令的角色如何,它都将以超级用户权限执行.

SET client_min_messages TO WARNING;告诉PostgreSQL的打压消息,如果该表不能被丢弃.可以删除这一行.

CREATE TEMP TABLE用于创建并不需要坚持一段时间的表.如果需要永久表,请删除TEMP修饰符.

'find...'命令也可以/usr/bin/find只列出files(type -f)并仅显示文件名,而前导路径每行只分隔一个文件名(-printf "%f\n").最后,-maxdepth 1将文件搜索限制为仅指定的目录,而不搜索任何子目录.有关详细信息,请参见find的手册页.


这种方法的一个缺点是似乎没有办法参数化要执行的命令.似乎PostgreSQL要求它是文本字符串,而不是表达式语句.也许这是最好的,因为它阻止允许执行任意命令.你看到的是你执行的.


Dan*_*ité 6

它通常对SQL客户端没用.

无论如何,你需要实现它,这是脚本语言的典型用例plperlu.例:

CREATE FUNCTION nosecurity_ls(text) RETURNS setof text AS $$
  opendir(my $d, $_[0]) or die $!;
  while (my $f=readdir($d)) {
    return_next($f);
  }
  return undef; 
$$ language plperlu;
Run Code Online (Sandbox Code Playgroud)

除了限制之外,这相当于系统管理功能中pg_ls_dir(text)提到的功能.


  => select * from nosecurity_ls('/var/lib/postgresql/9.1/main') as ls;
Run Code Online (Sandbox Code Playgroud)
      ls      
-----------------
 pg_subtrans
 pg_serial
 pg_notify
 pg_clog
 pg_multixact
 ..
 base
 pg_twophase
 etc...


Hub*_*tus 6

这个答案的扩展版本,函数ls_files_extended:

-- Unfortunately that variant only allow use hardcoded path
-- To use user parameter we will use dynamic EXECUTE.
-- Return also file size and allow filtering
--
-- @param path text. Filesystem path for read to
-- @param filter text (default null meaning return all). Where condition to filter files. F.e.: $$filename LIKE '0%'$$
-- @param sort text (default filename).
--
-- Examples of use:
-- 1) Simple call, return all files, sort by filename:
-- SELECT * FROM ls_files_extended('/pg_xlog.archive')
-- 2) Return all, sort by filesize:
-- SELECT * FROM ls_files_extended('/pg_xlog.archive', null, 'size ASC')
-- 3) Use filtering and sorting:
-- SELECT * FROM ls_files_extended('/pg_xlog.archive', 'filename LIKE ''0%''', 'size ASC')
-- or use $-quoting for easy readability:
-- SELECT * FROM ls_files_extended('/pg_xlog.archive', $$filename LIKE '0%'$$, 'size ASC')
CREATE OR REPLACE FUNCTION ls_files_extended(path text, filter text default null, sort text default 'filename')
    RETURNS TABLE(filename text, size bigint) AS
$BODY$
BEGIN
  SET client_min_messages TO WARNING;
  CREATE TEMP TABLE _files(filename text, size bigint) ON COMMIT DROP;

  EXECUTE format($$COPY _files FROM PROGRAM 'find %s -maxdepth 1 -type f -printf "%%f\t%%s\n"'$$, path);

  RETURN QUERY EXECUTE format($$SELECT * FROM _files WHERE %s ORDER BY %s $$, concat_ws(' AND ', 'true', filter), sort);
END;
$BODY$ LANGUAGE plpgsql SECURITY DEFINER;
Run Code Online (Sandbox Code Playgroud)