【发布时间】:2011-08-18 22:50:43
【问题描述】:
我遇到了针对 SQLite3 数据库的 DBIx::Class 问题。
如果您不想完整阅读以下内容,这里是 TL;DR 版本:
在比较时,有没有办法强制 DBD::SQLite 将整数字段视为无符号字段?
表定义在这里:
sqlite> PRAGMA table_info(entry);
0|entry_key|INTEGER|1||1
1|node|varchar(256)|1||0
2|object_type|varchar(128)|1||0
3|object_id|int|1||0
4|copy_id|tinyint|0||0
5|seq_number|int|1||0
6|root_seq_number|int|1||0
7|first_error|int|1||0
8|last_error|int|1||0
9|error_count|int|1||0
10|error_id|int|1||0
11|error_code|int|0||0
12|status|varchar(64)|1||0
13|type|varchar(64)|1||0
14|sense|char(256)|0||0
感兴趣的字段是first_error 和last_error。这些字段包含纪元时间值。 因此,它们是 32 位数字,但小于 2147483647
在我的代码中,我有以下内容:
my @entries = $self->{row}->search_related_rs('eventlog_entries')
->search_related('entry', {
first_error => {'>', $range->{start}},
last_error => {'<', $range->{end}},
}
)->all();
start 设置为 0; end 设置为 2**32 - 1
当使用DBI_TRACE=1 运行时,我得到:
<- prepare_cached('SELECT entry.entry_key, entry.node, entry.object_type,
entry.object_id, entry.copy_id, entry.seq_number,
entry.root_seq_number, entry.first_error, entry.last_error,
entry.error_count, entry.error_id, entry.error_code, entry.status,
entry.type, entry.sense FROM eventlog_entry me JOIN entry entry ON
entry.entry_key = me.entry_key WHERE ( ( ( first_error > ? AND
last_error < ? ) AND me.eventlog_key = ? ) )',
HASH(0x2472b54), ...)= ( DBI::st=HASH(0x2442efc) ) [1 items]
at DBI.pm line 2245
<- bind_param(1, 0, ...)= ( 1 ) [1 items] at DBI.pm line 1574
<- bind_param(2, '4294967295', ...)= ( 1 ) [1 items] at DBI.pm line 1574
<- bind_param(3, 1, ...)= ( 1 ) [1 items] at DBI.pm line 1574
<- execute= ( '0E0' ) [1 items] at DBI.pm line 1586
<- fetchall_arrayref= ( [ ] ) [1 items] row-1 at Cursor.pm line 133
在这种情况下,@entries 是一个空数组。
另一方面,如果我将end 设置为2**31 - 1,一切正常。
我的假设是这样的:
SQLite 字段具有“关联性”,这意味着字段被识别为整数,但它们没有原生大小。因此,SQLite 根据字段的内容“猜测”大小是多少。由于last_error 字段中的值小于 2147483647,但大于 16777215,我猜测 SQLite 将该字段视为带符号整数(即带符号的 32 位数字)。
因此,我的猜测是,当 bind_param 发生时,会进行某种检查,这会导致 DBI 将 last_error 识别为有符号整数。结果,4294967295 的值溢出,或者被压为零,或者类似的东西,并且比较不正确。
因此,我的问题:
- 这个假设是否正确(根据我忽略的一些文档)?或
- 有没有办法证实这个假设?
- 这是一个错误,还是有一个合理的解决方法,记住我使用的是 DBIx::Class,所以我从数据库中抽象出来了。
【问题讨论】:
-
您对“亲和力”类型是正确的。请参阅 sqlite 数据类型文档 (sqlite.org/datatype3.html) 中的第 2.0 节“类型关联”部分 sqlite 始终将整数视为无符号,所以我认为问题出在
DBD::SQLite -
实际上,仔细观察,我看到:“INTEGER。该值是一个有符号整数,根据值的大小存储在 1、2、3、4、6 或 8 个字节中。 “...所以 INTEGER 被签名...所以问题实际上是推断的大小。
-
对不起 - 我的意思是说“sql总是将整数视为有符号”而不是“无符号”:-)
标签: perl sqlite comparison integer dbi