.Net版SQLite无法访问网络位置的数据库文件-winOpen,os_win.c 36702错误

.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项目,可以输入数据库链接:
.Net版SQLite无法访问网络位置的数据库文件-winOpen,os_win.c 36702错误

点击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版:
下载

转载请注明出处。

(全文完)

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

发现之前提供的下载库x86版本编译有些问题。现已重新编译,且SQLite.Interop.dll均编译为静态链接,方便迁移使用。谢谢。


 

1楼arg
赞个!