考虑一个简单的mysql表,列id
(整数)和flag
(布尔值)。
用JavaScript编写的用户界面通过JSON与CGI后端通信,用于接收表中的数据并进行更新。
现在,在将数据{id: 5, flag: true}
发送到服务器时,我当然使用from_json
来获取perl哈希(ref)。然后
my $sth = $dbh->prepare('UPDATE my_table SET flag = ? WHERE id = ?);
$sth->execute($data->{flag}, $data->{id});
总是导致插入错误值。我相信这是因为JSON :: true和JSON :: false的神奇行为,分别串联为'true'和'false'(但会编号为1和0)。显然,execute语句提供字符串上下文,而不是数字上下文,因此mysql服务器接收不包含数字的字符串,然后导致插入值0。目前,我通过在? 1 : 0
之后添加$data->{flag}
来解决此问题。
在另一个方向,发生了相反的错误:根据DBI的文档,“大多数数据作为字符串返回到Perl脚本。”,所以当我用to_json
查看SELECT查询的结果时, UI将这些值作为JavaScript字符串“0”和“1”接收,这在JavaScript中都是正确的。所以现在我在应用$_->{flag} += 0 foreach (@result)
之前做了to_json
。
问题:我应该在链中的哪个点插入这些'黑客'?在JavaScript端,我可以确保发送值1和0而不是true和false,并将标志重新读取为数字。有什么我可以告诉DBI使它返回数字列(JSON认为的标量)数字?
答案 0 :(得分:3)
去过那里并做到了。最初我在我们在Perl中解码的JSON中添加了0,但是它很烦人且耗时,因为我不得不循环一个大的结构,为所有数字添加0。然后我帮助Tim Bunce将sql_type_cast添加到DBI中,以便对DBD :: Oracle进行一些小的更改可以使用它来返回数字而不是字符串(它们仍然是Perl标量,但有一些内部修改 - 见下文)。 / p>
我遇到的问题是我使用的是JSON :: XS,它查看encode_json中的标量,看看是否设置了pv或iv来决定是否在编码的JSON中生成“0”或0。 DBI的sql_type_cast和新的DBIstcf_DISCARD_STRING属性意味着我现在将数字列绑定为$ s-> bind_col(1,\ my $ col,{TYPE => SQL_INTEGER,DiscardString => 1}),sql_type_cast将删除标量的pv if它看起来像一个数字。问题是DBD需要更改为使用sql_type_cast。 DBD :: Oracle已更改,我只是在1.31中更改了DBD :: ODBC来执行此操作。
也许你可以用同样的方式改变DBD :: mysql或者说服其他人(我不使用mysql)。
有关DiscardString等实施的详细讨论,请参阅here。
你可以在DBD :: ODBC中找到一个名为sql_type_cast.t的测试,测试DiscardString在不使用JSON :: whatever的情况下工作。