COPY
命令加上文件名可以直接让PostgreSQL服务器从文件中读取或写入数据。文件必须可被PostgreSQL用户(即服务器运行的用户ID)访问,且文件名必须从服务器的视角指定。(来源:postgresql documentation)
因此,该文件应该由运行PostgreSQL服务器的Unix用户可读(或可写),而不是您的用户!为确保绝对正确性,您可以尝试运行sudo -u postgres head /tmp/test.csv
(假设您被允许使用sudo
,并且数据库用户为postgres)。
如果失败了,可能与SELinux有关(正如Craig Ringer所提到的)。在最常见的SELinux策略(Red Hat/Fedora/CentOS、Scientific Linux、Debian等使用的“targeted”参考策略)下,PostgreSQL服务器进程受限制:它只能读/写少数文件类型。
否认可能不会被记录在auditd的日志文件(
/var/log/audit/audit.log
)中,因为存在donaudit规则。因此,通常的SELinux快速测试适用,例如:通过运行
getenforce;setengorce 0;getenforce
停止SELinux约束任何进程,然后测试postgresql的
COPY
。然后通过运行
setenforce 1
重新激活SELinux(这个命令修改运行状态而不是配置文件,所以SELinux将在重启后处于活动状态(强制执行)。
修复问题的正确方法是更改要加载的文件的SELinux上下文。一个快速的hack是运行:
chcon -t postgresql_tmp_t /tmp/a.csv
但是,如果文件系统重新标记或创建新文件,则此文件标记将无法保存。您需要创建一个带有SELinux文件上下文映射的目录:
which semanage || yum install policycoreutils-python
semanage fcontext -a -t postgresql_tmp_t '/srv/psql_copydir(/.*)?'
mkdir /srv/psql_copydir
chmod 750 /srv/psql_copydir
chgrp postgres /srv/psql_copydir
restorecon -Rv /srv/psql_copydir
ls -Zd /srv/psql_copydir
任何在该目录中创建的文件都应该自动具有正确的文件上下文,以便postgresql服务器可以读/写它。(要检查postgres正在运行的SELinux上下文,请运行
ps xaZ | grep "postmaste[r]" | grep -o "[a-z_]*_t"
,这应该会打印出
postgresql_t
。要列出
postgresql_t
可以写入的上下文类型,请使用
sesearch -s postgresql_t -A | grep ': file.*write'
命令。命令
sesearch
属于
setools-console
RPM包)。
ls -l filename
和ls --lcontext filename
)、表权限(在psql
中使用\d+ tablename
)、您运行的确切命令文本+错误消息将会很有帮助。 - Craig Ringer