如何在DBI-> connect的参数中使用空格?

时间:2015-12-16 17:03:08

标签: perl dbi

我尝试使用DBIDBD::Pg连接SSL客户端密钥。

use strict;
use warnings 'all';
use DBI;

my $dsn = "dbi:Pg:db=mydb;sslmode=require;host=localhost;"
    ."sslcert=C:\\path with\\spaces.crt;"
    ."sslkey=C:\\path with\\spaces.key";

my $dbh = DBI->connect( $dsn, 'username', '' );

我收到以下错误:

Can't connect to database: missing "=" after "with\spaces.crt" in connection info string!

我尝试在值周围使用单引号或双引号无效,我在文档中找不到任何内容。

更新

单引号如下:

my $dsn = "dbi:Pg:db=mydb;sslmode=require;host=localhost;"
    ."sslcert='C:\\path with\\spaces.crt';"
    ."sslkey='C:\\path with\\spaces.key'";

我收到以下错误:

failed: FATAL:  connection requires a valid client certificate

我知道这种配置有效,因为它适用于Python。

事实证明这有效:

my $dsn = "dbi:Pg:db=mydb;sslmode=require;host=localhost;"
    ."sslcert='C:\\\\path with\\\\spaces.crt';"
    ."sslkey='C:\\\\path with\\\\spaces.key'";

为什么我需要双重转义反斜杠?

2 个答案:

答案 0 :(得分:3)

要在DSN中包含包含空格的属性,请使用单引号括起该值:

my $dsn = q{dbi:Pg:db=mydb;sslmode=require;host=localhost;}
        . q{sslcert='C:\\\path with\\\spaces.crt';}
        . q{sslkey='C:\\\path with\\\spaces.key'};

请注意,用于分隔连接属性的分号必须单引号之外。另请注意,属性中的反斜杠和单引号必须使用反斜杠进行转义(因为Perl会在单引号字符串中将\\转换为\,所以必须使用上面的三个反斜杠。)

如果您的DSN用双引号括起来,则必须使用四个反斜杠,因为Perl在双引号字符串中插入了\n之类的转义序列:

my $dsn = qq{dbi:Pg:db=mydb;sslmode=require;host=localhost;}
        . qq{sslcert='C:\\\\path with\\\\spaces.crt';}
        . qq{sslkey='C:\\\\path with\\\\spaces.key'};

至于文档,我没有在DBD :: Pg中看到这一点,但你可以看到它是通过查看源代码来支持的。处理DSN的代码位于DBD :: Pg发行版中的dbdimp.c

    /* DBD::Pg syntax: 'dbname=dbname;host=host;port=port', 'User', 'Pass' */
    /* libpq syntax: 'dbname=dbname host=host port=port user=uid password=pwd' */

...

    /* Change all semi-colons in dbname to a space, unless single-quoted */
    dest = conn_str;
    while (*dbname != '\0') {
            if (';' == *dbname && !inquote)
                    *dest++ = ' ';
            else {
                    if ('\'' == *dbname)
                            inquote = !inquote;
                    *dest++ = *dbname;
            }
            dbname++;
    }
    *dest = '\0';

这会将DBI样式的连接字符串转换为libpq-style connection string(libpq是Postgres C API,DBD :: Pg在后台使用它)。由于生成的DSN直接传递给libpq,因此需要遵循libpq documentation中描述的引用和转义规则。

DBD :: Pg的文档补丁肯定是有序的。

答案 1 :(得分:1)

问题在于空间。目前尚不清楚是否可以提供其中有空格的路径。如果是,它可能是特定于驱动程序的语法。您可能需要深入研究DBI和/或DBD :: Pg以确定语法是否受支持。有些人已经这样做,并在评论中提到您可以使用以下内容:

my $dsn = join(';',
   "dbi:Pg:db=mydb",
   "sslmode=require",
   "sslcert='$ssl_cert_qfn'",
   "sslkey='$ssl_key_qfn'",
);

或者您可以从另一个角度解决问题。 Windows具有向后兼容性系统,允许仅支持DOS样式路径的应用程序。值得注意的是DOS并没有允许路径中的空格。通过使用DOS样式的路径,您可以避免此问题。

use Win32 qw( );

my $dsn = join(';',
   "dbi:Pg:db=mydb",
   "sslmode=require",
   "sslcert=".Win32::GetShortPathName($ssl_cert_qfn),
   "sslkey=".Win32::GetShortPathName($ssl_key_qfn),
);

另一种解决方案是使用DBD::Pg's documentation中详述的配置文件。