這陣子在為Dbexpress Driver for SQL Server的選擇在測試著,進行到Debug DataSetProvider.OnBeforeUpdateRecord事件時,卻意外的發現各家的Driver在對Thread使用上的處理都不盡相同,於是做了點小小的研究。
2013/08/19
2013/08/07
DataSnap 應用中 Variant 會傻傻分不清 NULL 和 Empty String 的問題
這個問題會在 Delphi 7 ~ 2009 版本上出現,官方雖然說在 Delphi2009 的 SP4 (Database pack update) 上修正完成,但實際上卻是依然無解。
要還原現場也十分簡單,照著
Report #: 8482 TWidestring seems to convert empty strings to NULL
的步驟做就可以輕鬆重現經典bug。
於是我也依樣劃葫蘆地再發一次,只是角色換成了DBEXPRESS元件而已。
Report #117649 [SQL Server, NVARCHAR] TWideStringField seems to convert empty strings to NULL
想不到當天就有了回覆了,不知道是不是官方人員的回覆,但一整個感動啊!
回文的內容簡貼如下:
I tested your case with Delphi XE2 Update4 with SQL Server 2008 R2 on Windows 7. But, the error does not occur.
I will check the internal status of QC#67982 etc..
簡單的說,在「QC#67982」早就已經修補了這個Bug。
那QC#67982是什麼東西? 查了好久才知道原來是打包成「Delphi 2009 Update4」了。
但現實是並沒有解決我的問題啊!!!
接著就看到了這篇:
Report #71984 ApplyUpdates with empty string fields yields null values in where clause
看來是轉成SQL的時侯出怪手了,那到底DataSetProvider到底轉了什麼資料出來呢?
*使用 Open Dbexpress + SQLMonitor 擷錄結果:
ISQLCommand.SetParameter: 1; value: 1 INPUT WVARCHAR: '124'
ISQLCommand.SetParameter: 2; value: 2 INPUT INTEGER: 1
ISQLCommand.SetParameter: 3; value: 3 INPUT WVARCHAR: '0001'
ISQLCommand.Execute: update "DemoData" set
"SubCode" = ?
where
"DemoID" = ? and
"DemoCode" = ? and
"SubCode" is null
你你你…… SubCode 明明是not null、是empty string('')啊!你這個 NULL 跑出來是要鬧場的啊!
找到問題了,那就來解決吧!
照著剛剛的 Report #71984 也的確是能解決這個問題,修改Provider.pas後的擷取結果如下:
ISQLCommand.SetParameter: 1; value: 1 INPUT WVARCHAR: '124'
ISQLCommand.SetParameter: 2; value: 2 INPUT INTEGER: 1
ISQLCommand.SetParameter: 3; value: 3 INPUT WVARCHAR: '0001'
ISQLCommand.Execute: update "DemoData" set
"SubCode" = ?
where
"DemoID" = ? and
"DemoCode" = ? and
("SubCode" is null or "SubCode" = '''')
果真是解決了這個問題,但SQL看起來怪怪的。問題似乎不在Provider身上。
真正的原因是:
WHERE底下出現了「IS NULL」。那也就是TField.OleValue得到了應為「Empty String」的Variant 卻回傳了「NULL」詭異情形。
既然2010後已經解決,那就別理這個問題吧。
開玩笑的。
其實還好Delphi的Variants單元寫得很好,有幾個判斷的function,就直接放上Code吧。
如此一來問題就暫時得到解決了。
不過,能升級還是盡可能升級到XE以上的版本吧!
哎呀!原來是CodeGear的錯! |
要還原現場也十分簡單,照著
Report #: 8482 TWidestring seems to convert empty strings to NULL
的步驟做就可以輕鬆重現
於是我也依樣劃葫蘆地再發一次,只是角色換成了DBEXPRESS元件而已。
Report #117649 [SQL Server, NVARCHAR] TWideStringField seems to convert empty strings to NULL
想不到當天就有了回覆了,不知道是不是官方人員的回覆,但一整個感動啊!
回文的內容簡貼如下:
I tested your case with Delphi XE2 Update4 with SQL Server 2008 R2 on Windows 7. But, the error does not occur.
I will check the internal status of QC#67982 etc..
簡單的說,在「QC#67982」早就已經修補了這個Bug。
那QC#67982是什麼東西? 查了好久才知道原來是打包成「Delphi 2009 Update4」了。
我使用的版本早已經是 Last Version 了 |
接著就看到了這篇:
Report #71984 ApplyUpdates with empty string fields yields null values in where clause
看來是轉成SQL的時侯出怪手了,那到底DataSetProvider到底轉了什麼資料出來呢?
*使用 Open Dbexpress + SQLMonitor 擷錄結果:
ISQLCommand.SetParameter: 1; value: 1 INPUT WVARCHAR: '124'
ISQLCommand.SetParameter: 2; value: 2 INPUT INTEGER: 1
ISQLCommand.SetParameter: 3; value: 3 INPUT WVARCHAR: '0001'
ISQLCommand.Execute: update "DemoData" set
"SubCode" = ?
where
"DemoID" = ? and
"DemoCode" = ? and
"SubCode" is null
你你你…… SubCode 明明是not null、是empty string('')啊!你這個 NULL 跑出來是要鬧場的啊!
找到問題了,那就來解決吧!
照著剛剛的 Report #71984 也的確是能解決這個問題,修改Provider.pas後的擷取結果如下:
ISQLCommand.SetParameter: 1; value: 1 INPUT WVARCHAR: '124'
ISQLCommand.SetParameter: 2; value: 2 INPUT INTEGER: 1
ISQLCommand.SetParameter: 3; value: 3 INPUT WVARCHAR: '0001'
ISQLCommand.Execute: update "DemoData" set
"SubCode" = ?
where
"DemoID" = ? and
"DemoCode" = ? and
("SubCode" is null or "SubCode" = '''')
果真是解決了這個問題,但SQL看起來怪怪的。問題似乎不在Provider身上。
真正的原因是:
WHERE底下出現了「IS NULL」。那也就是TField.OleValue得到了應為「Empty String」的Variant 卻回傳了「NULL」詭異情形。
既然2010後已經解決,那就別理這個問題吧。
開玩笑的。
其實還好Delphi的Variants單元寫得很好,有幾個判斷的function,就直接放上Code吧。
if VarIsStr(ClientdataSet1.Fields[0].OldValue) then Result := VarToStr(ClientdataSet1.Fields[0].OldValue);
如此一來問題就暫時得到解決了。
不過,能升級還是盡可能升級到XE以上的版本吧!
訂閱:
文章 (Atom)