简体   繁体   English

使用Perl DBI无法打印的SQL Server时间戳字段

[英]SQL Server timestamp fields coming out unprintable with Perl DBI

I am connecting to an SQL Server 2014 database, via the Perl DBI module with DBD::ODBC. 我通过带有DBD :: ODBC的Perl DBI模块连接到SQL Server 2014数据库。 The table I'm looking at has the following structure: 我正在查看的表具有以下结构:

CREATE TABLE [dbo].[JonesFrank$EMSM Printouts](
    [timestamp] [timestamp] NOT NULL,
    [Document Type] [int] NOT NULL,
    [Document No_] [nvarchar](20) NOT NULL,
    [Line No_] [int] NOT NULL,
    [Entry No_] [int] NOT NULL,
    [Printout] [image] NULL,
    [Date] [datetime] NOT NULL,
 CONSTRAINT [JonesFrank$EMSM Printouts$0] PRIMARY KEY CLUSTERED 
(
    [Document Type] ASC,
    [Document No_] ASC,
    [Line No_] ASC,
    [Entry No_] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

As you can see, it has a timestamp column, cleverly named 'timestamp'. 如您所见,它有一个timestamp列,巧妙地命名为“ timestamp”。 When I select values from this table within the SQL Server application, they come out as long hex numbers, like so: 当我从SQL Server应用程序的此表中选择值时,它们以十六进制数字形式出现,如下所示:

+====================+
| timestamp          |
+====================+
| 0x000000000AA531FB |
| 0x000000000AB0F485 |
| 0x000000000AB0F483 |
| 0x000000000A941C0C |
| 0x000000000AA531F5 |
| 0x000000000AA53448 |
+====================+

However, when I run a Perl program, using DBI and DBD::ODBC , the results are strings containing non-printable characters: 但是,当我使用DBIDBD::ODBC运行Perl程序时,结果是包含不可打印字符的字符串:

#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Getopt::Long;

GetOptions (
   'dbname=s' => \my $dbname,
   'driver=s' => \my $driver,
   'server=s' => \my $server,
   'user=s'   => \my $user,
   'pwd=s'    => \my $pwd,
) or die "Invalid command line options\n";

die "--dbname <database name> required!\n" unless defined $dbname;

$driver //= 'SQL Server';
$server //= 'SQL';
$user   //= 'xxx';
$pwd    //= 'xxxxxxxx';

my $table = 'TheTable';    

my $dbh = DBI->connect(
    "dbi:ODBC:Driver={$driver};Server=$server;UID=$user;PWD=$pwd",
    { RaiseError => 1}
) or die "Cannot connect: $DBI::errstr";

$dbh->do("use $dbname");

my $sql = "SELECT [timestamp] FROM [$table] WHERE Printout IS NOT NULL";
my $sth = $dbh->prepare($sql);
$sth->execute();
while (my $row = $sth->fetch()) {
   print $row->[0], "\n";
}

(I have to post the output as an image, as I don't know how to reproduce the strings that are output just by typing on my keyboard here...) (我必须将输出发布为图像,因为我不知道如何仅通过在此处输入键盘来重现输出的字符串...)

在此处输入图片说明

I am using perl 5.22.2 for cygwin, DBI.pm 1.636, and DBD/ODBC.pm 1.52. 我将cygwin,DBI.pm 1.636和DBD / ODBC.pm 1.52用于perl 5.22.2。

Does anyone know why the timestamp values are coming out like this, and how to get the 'real' values, that I see in the SQL Server application? 有谁知道为什么在SQL Server应用程序中会出现这样的时间戳值,以及如何获取“真实”值?

I can see the original data in the console output. 我可以在控制台输出中看到原始数据。 chr(0x0A) is a newline, chr(0xA5) is a weird character, chr(0x31) is the digit 1 , chr(0xFB) is another weird character, etc. chr(0x0A)是换行符, chr(0xA5)是一个怪异字符, chr(0x31)是数字1chr(0xFB)是另一个怪异字符, chr(0xFB)

So the 64-bit integer displayed in the SQL Server application is encoded in a string. 因此,SQL Server应用程序中显示的64位整数被编码为字符串。 And when you hear the words "integer", "string", and "encoding", then you should think "pack" and "unpack" . 当您听到单词“ integer”,“ string”和“ encoding”时,您应该考虑"pack""unpack"

After some trial-and-error, I find that the Perl code to recreate SQL Server's hex strings from the output to Perl looks like: 经过反复试验,我发现从输出到Perl重新创建SQL Server十六进制字符串的Perl代码如下所示:

sub rawTimestampToHex {
    my $i = shift;
    sprintf "0x%016X", unpack("Q>",$i);
}

where the "Q>" template means to interpret the first 8-bytes of input as a packed unsigned quad (64-bit integer) value in big-endian byte-order (most significant bits first) 其中"Q>"模板的意思是将输入的前8个字节解释为大端字节顺序的打包无符号四边形(64位整数)值(最高有效位在前)

Example: 例:

print rawTimestampToHex("\x00\x00\x00\x00\x0A\xA5\x31\xFB")
0x000000000AA531FB

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM