如何使用FreeTDS的TDSDUMP功能debug

有人遇到一個問題,說他的PHP程式連資料庫(MSSQL 2008R2)查詢資料時會因為 Changed database context to 'DATABASE-NAME' 的錯誤而無法執行…

"Changed database context to XXXX"這訊息的含意是…登入資料庫所用的帳號,做了切換資料庫的動作。如果登入資料庫的帳號有設定預設使用的資料庫,而程式運作中切換了資料庫。舉例,登入資料庫的帳號預設的資料庫為 DB-A,但程式登入資料庫後切換到 DB-B時,此時資料庫就會回傳這訊息。

雖然這樣的訊息不是『錯誤』,只能算是『資訊』…以往總覺得納悶這為何是錯誤?但,在這次追查問題中使用SQL Server Profiler時,發現到真的歸類於error...

總之,個人認為他的程式不可能是因為這的訊息樣而無法運作。且,他PHP程式所在的主機,都已經將錯誤等級設定為超過11才顯示,如下…
; Minimum error severity to display.
mssql.min_error_severity = 11
; Minimum message severity to display.
mssql.min_message_severity = 11
; Connect timeout
mssql.connect_timeout = 7
; Query timeout
mssql.timeout = 10

於是,開啟FreeTDS的TDSDUMP功能,藉由FreeTDS和資料庫間的log來找問題。設定方式如下…
# Whether to write a TDSDUMP file for diagnostic purposes
# (setting this to /tmp is insecure on a multi-user system)
dump file = /tmp/freetds.log
debug flags = 0xffff

在FreeTDS的log,看到"Adaptive Server connection timed out"的訊息。才知道原來是程式中的SQL語法執行太久,超過mssql.timeout(該主機設定為7秒)而被中斷。
15:59:04.555905 58895 (util.c:331):tdserror(0x802bbd640, 0x80dff0180, 20003, 0)
15:59:04.556101 58895 (dblib.c:7929):dbperror(0x80dfe7300, 20003, 0)
15:59:04.556129 58895 (dblib.c:7981):20003: "Adaptive Server connection timed out"
15:59:04.556157 58895 (dblib.c:8002):"Adaptive Server connection timed out", client returns 2 (INT_CANCEL)
15:59:04.556175 58895 (util.c:361):tdserror: client library returned TDS_INT_CANCEL(2)
15:59:04.556191 58895 (util.c:384):tdserror: returning TDS_INT_CANCEL(2)
15:59:04.556975 58895 (util.c:156):Changed query state from READING to DEAD

至於為何該SQL語法會執行如此的久?又是另一個故事…花了不少時間…

知道原因就好解決了,只要在執行這SQL語法前使用ini-set() 重新設定mssql.timeout,將秒數拉長即可。

對了。追查問題過程中發現一件事情。FreeTDS的TDSDUMP功能必須在CLI模式下才會有作用。如果是使用WEB模式執行,不會產生log。


參考資料

留言