如何在 DBI->connect 的参数中使用空格?
How do I use spaces in parameters for DBI->connect?
我正在尝试使用 DBI
和 DBD::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'";
为什么我需要双转义反斜杠?
问题是space。目前尚不清楚是否可以提供其中包含 space 的路径。如果是,则可能是特定于驱动程序的语法。您可能需要深入研究 DBI and/or DBD::Pg 以确定语法是否受支持。有些人已经这样做并在评论中提到您可以使用以下内容:
my $dsn = join(';',
"dbi:Pg:db=mydb",
"sslmode=require",
"sslcert='$ssl_cert_qfn'",
"sslkey='$ssl_key_qfn'",
);
或者你可以从另一个角度来解决这个问题。 Windows 有一个向后兼容系统,允许只支持 DOS 风格路径的应用程序。值得注意的是 DOS 不允许在路径中使用 spaces。通过使用 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 中详述的配置文件。
要在您的 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 != '[=12=]') {
if (';' == *dbname && !inquote)
*dest++ = ' ';
else {
if ('\'' == *dbname)
inquote = !inquote;
*dest++ = *dbname;
}
dbname++;
}
*dest = '[=12=]';
这会将 DBI 样式的连接字符串转换为 libpq-style connection string (libpq is the Postgres C API, which DBD::Pg uses behind the scenes). Since the generated DSN is passed straight to libpq, it needs to follow the rules for quoting and escaping described in the libpq documentation。
DBD::Pg 的文档补丁肯定是有序的。
我正在尝试使用 DBI
和 DBD::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'";
为什么我需要双转义反斜杠?
问题是space。目前尚不清楚是否可以提供其中包含 space 的路径。如果是,则可能是特定于驱动程序的语法。您可能需要深入研究 DBI and/or DBD::Pg 以确定语法是否受支持。有些人已经这样做并在评论中提到您可以使用以下内容:
my $dsn = join(';',
"dbi:Pg:db=mydb",
"sslmode=require",
"sslcert='$ssl_cert_qfn'",
"sslkey='$ssl_key_qfn'",
);
或者你可以从另一个角度来解决这个问题。 Windows 有一个向后兼容系统,允许只支持 DOS 风格路径的应用程序。值得注意的是 DOS 不允许在路径中使用 spaces。通过使用 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 中详述的配置文件。
要在您的 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 != '[=12=]') {
if (';' == *dbname && !inquote)
*dest++ = ' ';
else {
if ('\'' == *dbname)
inquote = !inquote;
*dest++ = *dbname;
}
dbname++;
}
*dest = '[=12=]';
这会将 DBI 样式的连接字符串转换为 libpq-style connection string (libpq is the Postgres C API, which DBD::Pg uses behind the scenes). Since the generated DSN is passed straight to libpq, it needs to follow the rules for quoting and escaping described in the libpq documentation。
DBD::Pg 的文档补丁肯定是有序的。