2011-08-18 48 views
1

我面臨DBIx :: Class針對SQLite3數據庫的問題。整數比較使用DBD :: SQLite

如果你不想讀滿了之後,這裏的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,一切正常。

我hyopthesis是這樣的:

SQLite的領域有一個「親」,這意味着該領域被認爲是整數,但他們沒有本土的大小。因此,SQLite根據字段的內容「猜測」大小。由於last_error字段中的值小於2147483647,但大於16777215,所以我猜測SQLite將該字段視爲SIGNED INTEGER(即帶符號的32位數字)。

因此,我的猜測是,當bind_param發生時,會進行某種檢查,導致DBI將last_error識別爲SIGNED INTEGER。結果,4294967295的值溢出,或被擠壓到零,或類似的東西,並且比較工作不正確。

因此,我的問題(S):

  1. 這是假設正確的(根據一些資料,我已經忽略了)?或
  2. 有沒有辦法確認這個假設?
  3. 這是一個錯誤,或者是有一個合理的解決辦法,記住,我使用DBIx ::類軸承,所以我有點抽象從數據庫了。
+0

你是對的類型'親和力'。請參閱sqlite數據類型文檔(http://www.sqlite.org/datatype3.html)中的第2.0節「類型相關性」。sqlite總是將整數視爲無符號,所以我認爲問題出現在'DBD :: SQLite' – ErikR

+0

實際上,仔細觀察後,我看到:「INTEGER。該值是一個有符號整數,根據值的大小存儲在1,2,3,4,6或8個字節中。」...因此INTEGER被簽名。 ..所以問題實際上是推斷的大小。 – Dancrumb

+0

對不起 - 我的意思是說「sql始終將整數視爲_signed_」而不是「unsigned」:-) – ErikR

回答

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的stringifies $range->[end}爲正數。

+0

我給你一個upvote,因爲這是一個有效的解決方案。但是,我仍然想要正確理解這裏發生的事情,以及是否有辦法解決根本問題。 – Dancrumb