使用DBD :: SQLite进行整数比较

时间:2011-08-18 22:50:44

标签: perl sqlite comparison integer dbi

我遇到了针对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_errorlast_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将字段视为SIGNED INTEGER(即带符号的32位数字)。

因此,我的猜测是,当bind_param发生时,会进行某种检查,这会导致DBI将last_error标识为SIGNED INTEGER。结果,4294967295的值溢出,或者被压缩到零或类似的东西,并且比较工作不正确。

因此,我的问题:

  1. 这个假设是否正确(根据我忽略的一些文件)?或
  2. 有没有办法证实这个假设?
  3. 这是一个错误,还是有一个合理的解决方法,请记住我正在使用DBIx :: Class,所以我有点抽象远离数据库。

1 个答案:

答案 0 :(得分:1)

如何在查询中使用文字sql:

my $cond = " < $range->{end} ";

my @entries =  $self->{row}->search_related_rs('eventlog_entries')
                       ->search_related('entry', {
                         first_error => {'>', $range->{start}},
                         last_error  => \$cond,
                       }
       )->all();

如果perl将$range->[end}字符串化为正数,则应该有效。