寻求帮助从Perl向Postgres发送查询

时间:2012-10-11 22:29:26

标签: perl

我正在尝试编写一个Perl脚本来启动一个Postgres客户端并通过客户端发送多个文件,分别为每个文件捕获输出。

如果我这样做:

system ("cat $query1.sql | psql -p 2070 super &> $HOME/Results1.txt");
system ("cat $query2.sql | psql -p 2070 super &> $HOME/Results2.txt");

然后Perl将为每个查询启动客户端。由于我将运行数百甚至数千个查询,因此我希望跳过启动除第一个客户端以外的所有开销。

我想我应该可以通过Open2启动Postgres客户端,但是当我尝试时它会挂起。我在使用Perl 5.10.0的SUSE Linux机器上执行此操作。

这是我的代码:

use IPC::Open2;

use IO::Handle;

our $pid = open2(*CHILDOUT, *CHILDINT, '../installdir/bin/psql -p 2070 super');
print STDOUT $pid;

print CHILDINT "cat $dumpR5KScript";
print STDOUT 'Sent the commands';

$output = <CHILDOUT>;

close(CHILDIN);
close(CHILDOUT);

似乎挂着“open2”,因为我从未见过这个pid。

有人可以指出我做错了什么,所以我对open2的调用没有挂起吗?

如果有人就提出Postgres客户端并通过它运行查询的最佳方式提出建议,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

您已经被告知在帖子的评论中使用DBI,如果您这样做,这将是一件好事。格式化很多比摆弄IPC更容易,并在Perl和命令行数据库客户端之间拼接一种API,解析输出并格式化输入。

关于你的问题,但是:

  1. 应该是\*CHILDIN而不是*CHILDIN(引用typeglob而不是typeglob)
  2. 无论如何在这种情况下你应该使用变量而不是typeglobs和古代习语:

    my ( $childout, $childin ) ;
    our $pid = open2( $childout, $childin, '../installdir/bin/psql -p 2070 super');
    print STDOUT $pid;
    
  3. 请阅读IPC::Open2
  4. 的文档
  5. 此外,最好还使用open3来处理STDERR
  6. 最后,我不知道postgress客户端,但是open2可能会出现死锁(你遇到的情况)非常真实:
  7.   

    这整个事件非常危险,因为你可能永远阻止。它假设它会与bc这样的东西交谈,既写入它又从中读取。这可能是安全的,因为你“知道”像bc这样的命令会一次读取一行并一次输出一行。然而,首先读取整个输入流的排序等程序很容易导致死锁。

         

    这种方法的一个大问题是,如果您无法控制在子进程中运行的源代码,则无法控制它对管道缓冲的作用。因此,你不能只打开一个管道来管理-v并不断地从中读取和写入一行。

         

    CPAN的IO :: Pty和Expect模块可以帮助解决这个问题,因为它们提供了一个真正的tty(实际上是伪tty),它可以让你再次回到被调用命令的行缓冲。