我正在尝试使用DBI和连接SSL客户端密钥DBD::Pg.
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', '' );
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
Can't connect to database: missing "=" after "with\spaces.crt" in connection info string!
Run Code Online (Sandbox Code Playgroud)
我试过在值周围使用单引号或双引号无效,我在文档中找不到任何内容.
单引号如下:
my $dsn = "dbi:Pg:db=mydb;sslmode=require;host=localhost;"
."sslcert='C:\\path with\\spaces.crt';"
."sslkey='C:\\path with\\spaces.key'";
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
failed: FATAL: connection requires a valid client certificate
Run Code Online (Sandbox Code Playgroud)
我知道这个配置有效,因为它适用于Python.
事实证明这是有效的:
my $dsn = "dbi:Pg:db=mydb;sslmode=require;host=localhost;"
."sslcert='C:\\\\path with\\\\spaces.crt';"
."sslkey='C:\\\\path with\\\\spaces.key'";
Run Code Online (Sandbox Code Playgroud)
为什么我需要双逃逸反斜杠?
要在 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'};
Run Code Online (Sandbox Code Playgroud)
请注意,用于分隔连接属性的分号必须位于单引号之外。另请注意,属性内的反斜杠和单引号必须使用反斜杠进行转义(您必须使用上面的三个反斜杠,因为 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'};
Run Code Online (Sandbox Code Playgroud)
至于文档,我没有看到 DBD::Pg 中提到这一点,但您可以通过查看源代码看到它是支持的。处理 DSN 的代码位于DBD::Pg 发行版的dbdimp.c中:
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'};
Run Code Online (Sandbox Code Playgroud)
这会将 DBI 样式的连接字符串转换为libpq 样式的连接字符串(libpq 是 Postgres C API,DBD::Pg 在幕后使用它)。由于生成的 DSN 直接传递给 libpq,因此它需要遵循libpq 文档中描述的引用和转义规则。
DBD::Pg 的文档补丁肯定是合适的。