2

我有一个包含各种插入语句和偶尔的“\connect”命令的数据库转储文件

问题是它PG::Connection.exec()不接受 psql 的\-command 之类的\ior\c等​​。

有没有办法使用 ruby​​-pg(或者可能是另一个 pg-gem)来完成这项工作?

由于数据库位于不同的主机上,我无法使用 Unix 套接字,因此无法以postgres没有密码的用户身份连接。

4

3 回答 3

1

只使用pg_restore之类的 psql 命令行工具可能更容易:

pg_restore -d newdb db.dump

如果您对托管原始数据库的框具有 ssh 访问权限并且知道需要转储哪个表,则可以 ssh 进入该框并将pg_dump输出直接通过管道传输到本地数据库。就像是:

ssh user@original_database pg_dump -U remote_user_name -T schema_name.table_name mydb | psql -U local_user_name -d local_database
于 2012-07-12T17:38:10.190 回答
0

答案是“否”,因为反斜杠命令不是 Postgres 命令。它们是psql命令,这是默认的命令行客户端。没有第三方工具会复制这些命令,因为它们不是libpq API 的一部分。

现在,也就是说,是 \connect 文件中唯一的反斜杠命令吗?如果是这样,那么您应该能够通过从 \connect 语句中解析出数据库名称来实现这一点,然后从每个 \connect 语句之后的第一行开始将转储文件拆分为块。此时,只需针对该块的 \connect 语句中给定的数据库连接正常运行每个块。

据我所知,如果不创建新连接,就无法重新连接到不同的数据库,因为必须重新验证用户的凭据。这就是 psql 在幕后的工作方式。

还有另一种想法,如果只有一个 \connect 语句,并且它紧跟在 CREATE DATABASE 语句之后,即紧随 CREATE ROLE 之类的语句之后,那么如果您将数据库创建为一个单独的步骤并从中删除 CREATE DATABASE 和 \connect 语句该文件,您可以在不分块的情况下执行此操作。请记住,您仍然需要两个连接,因为在创建数据库之前您无法连接到数据库,并且在连接到新数据库的过程中仍然无法更改。

于 2012-07-12T19:13:01.547 回答
0

在尝试了很多东西之后,包括在 \connect 行拆分文件等,我最终暂时将其使用了“老式的 shell 脚本方式”......这是我想要避免的方式。但我必须去某个地方

我现在正在做的事情如下:

  insert_command = "cat #{dump_file_path} | " +
        "ssh -p #{port} -i #{key} #{ssh_user}@#{db_host} " +
        "\"su - postgres -c 'cat > /tmp/rb_dump.sql && psql -f /tmp/rb_dump.sql ; rm /tmp/rb_dump.sql'\""

    Open3.popen3 insert_command do |stdin, stdout, stderr, t|
      unless t.value.to_s.include? "exit 0"
        <handle error>
      end
    end

在我看来,这完全是 hacky,但它确实有效 ^^

我的另一个解决方案是下一个代码,它有一个大问题(如下所述)

 def insert_database_dump(dump_file_handle, host, user, password, database = nil)
    begin
      pg = PG.connect(host: host, user: user, password: password, dbname: database)
      until dump_file_handle.eof?
        line = dump_file_handle.readline(";")
        if line =~ /connect\s(\w*)/
          line.gsub!("\\connect", "").strip!
          insert_database_dump(dump_file_handle, host, user, password, line)
        else
          pg.exec(line)
        end
      end
    ensure
      pg.finish unless pg.finished?
    end
  end

该代码执行以下操作(仅重要部分):

  • 从 sql 中读取一行,直到 ";" (查询被分成几行,所以在换行之前阅读是行不通的
  • 执行查询
  • 如果该行看起来像“连接单词”,则选择“单词”作为数据库名称,并使用“单词”作为数据库名称再次调用该方法,并且当前文件句柄指向我想要的正确行继续。

尽管方法可能有更优雅的方式来调用自身,但除非 sql 转储中有注释,否则这种方法是有效的。问题是评论看起来像这样:

-- foo: bar; bam: baz;

因此,当使用“;”进行拆分时,它会执行“-- foo: bar;”,因为它是一个注释,但由于“bam: baz;”而失败。

我目前没有简单的解决方案来即时删除评论行。所以 Open3 解决方案将不得不做,直到我发现。

干杯,斯特凡

于 2012-07-16T13:52:14.083 回答