使用ruby-pg插入数据库转储

时间:2012-07-12 17:03:44

标签: ruby postgresql dump psql

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

问题是PG::Connection.exec()不接受psql的\ - \i\c等命令。

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

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

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

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

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

据我所知,由于必须重新验证用户的凭据,因此无法在不创建新连接的情况下重新连接到其他数据库。这甚至是psql在幕后做的。

还有另外一个想法,如果只有一个\ connect语句,它紧跟在CREATE DATABASE语句之后,紧接在CREATE ROLE之类的语句之后,那么如果你创建数据库作为一个单独的步骤并同时删除CREATE DATABASE和\连接文件中的语句,你可以在没有分块的情况下完成它。请记住,您仍然需要两个连接,因为在创建数据库之前无法连接到数据库,并且仍然无法在中间连接中更改为新数据库。

答案 2 :(得分: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读取一行直到“;” (查询分为几行,因此只读到换行符
  • 执行查询
  • 如果该行看起来像“连接字”,则选择“word”作为数据库名称,并使用“word”作为数据库名称再次调用该方法,并且当前文件句柄指向正确的行我想继续

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

-- foo: bar; bam: baz;

所以当用“;”分割时,它会执行“ - foo:bar;”,这是有效的,因为它是一个注释但是失败了“bam:baz;”

我目前没有简单的解决方案来动态删除评论行。所以Open3解决方案必须要做,直到找到。

干杯,  斯蒂芬