使用COPY

时间:2018-08-14 22:20:11

标签: python postgresql csv psycopg2

我正在使用python使用Psycopg2将csv数据转储到数据库中。为了使用COPY命令(文档:https://www.postgresql.org/docs/10/static/sql-copy.html),我需要授予Postgres对特定文件路径的权限。我需要授予特定目录路径路由和文件的权限,以避免出现以下错误:

COPY database.table_name FROM '/home/development_user/Documents/App/CSV/filename.csv' delimiter ',' csv header

ERROR:  could not open file "/home/development_user/Documents/App/CSV/filename.csv" for reading: Permission denied

为简化操作,要将postgres添加到开发用户组。这样,postgres应该具有组读取权限,开发用户可以轻松地逐条路径定义组读取权限。我使用以下命令将postgres用户添加到development_user组,并验证它是否成功:

$ sudo usermod -a -G development_user postgres
$ groups postgres
postgres : postgres development_user

以下是使用namei -l [path]逗号的权限路径跟踪的输出

$ namei -l /home/development_user/Documents/App/CSV/filename.csv
drwxr-xr-x root        root        /
drwxr-xr-x root        root        home
drwxr-x--- development_user development_user development_user
drwxr-xr-x development_user development_user Documents
drwxr-xr-x development_user development_user App
drwxrwxr-x development_user development_user CSV
-rw-rw-r-- development_user development_user filename.csv

如您所见,development_user组中的任何人现在都应该对路径中的所有目录具有读取(r)和执行(x)的权限,并且还必须进行读写最终文件的权限。如果postgres尝试与other用户访问同一文件,则postgres将受development_user目录的访问权限限制。

但是,当我尝试访问文件时,出现如上所述的权限错误。当我使用development_user的读取和执行权限(如下面的命令)打开other目录时,我能够读取文件为Postgres:

$ chmod o+rx /home/development

但是,我不想授予other对development_user主目录的读取和执行权限,并且我看不到为什么postgres用户不能使用上面概述的组权限来访问相同的文件因为我将postgres添加到了development_user帐户。

任何想法,如果我的方法通过将postgres权限添加到用户组中来授予其读取文件的权限的方法可行吗?我不想使用此处提到的其他解决方案:(PostgreSQL - inconsistent COPY permissions errors)或此处(Postgres ERROR: could not open file for reading: Permission denied),它们建议通过将文件所有者设置为postgres:postgres来建议开放权限。或广泛开放目录权限,例如允许所有用户在开发主目录上读取和执行。我也不想在系统目录中创建另一个目录,并被迫按照此处的建议在该目录中保存文件:(psql ERROR: could not open file "address.csv" for reading: No such file or directory)。

3 个答案:

答案 0 :(得分:1)

来自PostgreSQL Manual

  

COPY命名文件或命令仅允许数据库超级用户使用,   因为它允许读取或写入服务器具有的任何文件   访问权限。

因此,进行复制的PostgreSQL用户必须是数据库超级用户。

您可以使用ALTER ROLE命令来完成此操作:

ALTER ROLE <rolename> WITH SUPERUSER

也:

  

带有文件名的COPY指示PostgreSQL服务器直接读取   从文件或写入文件。该文件必须可由PostgreSQL访问   用户(服务器运行时使用的用户标识),并且必须指定名称   从服务器的角度来看。

     

...

     

在COPY命令中命名的文件可以由计算机直接读取或写入。   服务器,而不是客户端应用程序。因此,它们必须驻留在   或可供数据库服务器计算机而非客户端访问。

运行PostgreSQL的默认系统用户为postgres。确保该用户有权访问要复制的文件。您可以使用命令sudo -i -u postgres成为postgres用户,然后尝试查看文件来进行测试。

答案 1 :(得分:0)

我使用psychopg2游标类函数copy_expert(文档:http://initd.org/psycopg/docs/cursor.html)解决了这个问题的方法。 copy_expert允许您使用STDIN,因此无需为postgres用户颁发超级用户特权。

从Postgres COPY Docs(https://www.postgresql.org/docs/current/static/sql-copy.html):

  

请勿将COPY与psql指令\ copy混淆。 \ copy调用   从STDIN复制或复制到标准输出,然后在其中获取/存储数据   psql客户端可访问的文件。因此,文件可访问性和   \ copy时,访问权限取决于客户端而不是服务器   使用。

您还可以保留为访问development_user主文件夹和App文件夹而严格设置的权限。

            sql = "COPY table_name FROM STDIN DELIMITER '|' CSV HEADER"
            self._cursor.copy_expert(sql, open(csv_file_name, "r"))

答案 2 :(得分:0)

@jonnyjandles答案略有变化,因为这显示了一个神秘的self._cursor-更典型的调用可能是:

copy_command = f"COPY table_name FROM STDIN CSV HEADER;"
with connection.cursor() as cursor:
    cursor.copy_expert(copy_command, open(some_file_path, "r"))