.Net版SQLite無法訪問網絡位置的數據庫文件-winOpen,os_win.c 36702異常


最近一個C#小程序,希望將SQLite數據庫放在網絡共享的位置,讓多個客戶端同時訪問。卻發現SQLite連接不上該網絡位置的數據庫,而如果數據庫在本地則一切正常。

例如將SQLite數據庫 test.dat 放在共享位置:\\System\Data\test.dat
通過SQLite創建數據庫連接,執行Open時,將拋擲異常:

SQLite error (14): os_win.c:36702: (3) winOpen(D:\System\Data\test.dat) - 系統找不到指定的路徑。
SQLite error (14): os_win.c:36702: (3) winOpen(D:\System\Data\test.dat) - 系統找不到指定的路徑。
SQLite error (14): cannot open file at line 36711 of [9491ba7d73]
“System.Data.SQLite.SQLiteException”類型的第一次機會異常在 System.Data.SQLite.dll 中發生
System.Data.SQLite.SQLiteException (0x80004005): unable to open database file
   在 System.Data.SQLite.SQLite3.Open(String strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool)
   在 System.Data.SQLite.SQLiteConnection.Open()
   在 MyMemory.Frame.DAL.SQLiteRunner..ctor(String connectionString) 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\SQLiteRunner.cs:行號 34
   在 MyMemory.Frame.DAL.DatabaseServices.CreateConnection() 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\DatabaseServices.cs:行號 23
   在 MyMemory.Frame.DAL.DatabaseServices.Initialize(String dataDir) 位置 d:\Work\Program\WPF\MyMemory\MyMemory.Frame\DAL\DatabaseServices.cs:行號 54
“System.Data.SQLite.SQLiteException”類型的第一次機會異常在 MyMemory.Frame.dll 中發生
System.Data.SQLite.SQLiteException (0x80004005): unable to open database file
   在 System.Data.SQLite.SQLite3.Open(String strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, Int32 maxPoolSize, Boolean usePool)
   在 System.Data.SQLite.SQLiteConnection.Open()
   ...

即傳入的SQLite網絡共享路徑(以\\開頭)在SQLite內部某個環節被轉換成為了本地路徑!

問題處在SQLite提供的程序集內,那么SQLite最新版本是否已經修復這個問題了(或是從某版故意為之,不讓訪問網絡共享位置的文件了呢)?
到官網http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki下載最新版本( System.Data.SQLite 1.0.94.0 (3.8.6) )替換后重試,還是出現上面的異常。

好吧,既然是開源的,那就下載源代碼,看看是什么原因。

下載了之后,采用VS編譯,通過解決方案中自帶的Test項目,可以輸入數據庫鏈接:

點擊Run就可以進入斷點調試了。

廢話少說,直接上結果:

Open過程問題點的方法調用過程如下

\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConnection.cs Line 2372
SortedList<string, string> opts = ParseConnectionString(
          _connectionString, _parseViaFramework);

\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConnection.cs Line 1875
arParts = SQLiteConvert.NewSplit(s, ';', true, ref error);

\sqlite-netFx-source-1.0.94.1\System.Data.SQLite\SQLiteConvert.cs Line 716
if ((character != EscapeChar) &&
                    (character != QuoteChar) &&
                    (character != separator))

將上面的if ( //(character != EscapeChar) && 注釋掉后半行(注意:不推薦這種注釋代碼的方法)
                    (character != QuoteChar) &&
                    (character != separator))

再編譯,重新執行Test.exe 一切OK。

至於為什么有這個限制,源代碼中的注釋是:

                // --Line 709
                // HACK: Only consider the escape character to be an actual
                //       "escape" if it is followed by a reserved character;
                //       otherwise, emit the original escape character and
                //       the current character in an effort to help preserve
                //       the original string content.
                // --Line 715

官方文檔說,放在網絡位置共享訪問的SQLite數據庫,在某些特定情況下容易損壞。看來這個問題大神們解決不好,准備干脆屏蔽掉這種使用方式了。

提醒一下,SQLite源碼默認用的.Net Framework 4.5,編譯時注意切換為項目需要的.Net Framework版本。

最后提供修改后的System.Data.SQLite.dll .Net Framework 4.0版:
下載

轉載請注明出處:原文http://www.cnblogs.com/yangzhj/p/4230123.html

(全文完)

-------------------------------------------
2015-01-17 10:45 PS:

發現之前提供的下載庫x86版本編譯有些問題。現已重新編譯,且SQLite.Interop.dll均編譯為靜態鏈接,方便遷移使用。謝謝。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM