Excel/VBA 在尝试通过 ADODB/SQLiteODBC 更改 SQLite 数据库的日志模式时挂起

Excel/VBA hangs when trying to change journal mode of an SQLite database via ADODB/SQLiteODBC

下面的代码在 Temp 文件夹中创建一个新的空白 SQLite 数据库,创建一个 table,填充它,然后暂停。然后在DB Browser for SQLite中交互打开数据库,更改了一个值,但未提交更改。恢复执行,并且 Excel/VBA 在尝试通过 ADODB/SQLiteODBC.

更改日志模式时引发“数据库已锁定”错误之前挂起大约 1.5 分钟

澄清一下,此代码专门用于重现该问题。很清楚为什么会引发错误。问题是需要等待的时间。

Private Sub ConnectSQLiteAdoCommandSource()
    Dim Driver As String
    Driver = "SQLite3 ODBC Driver"
    Dim Database As String
    Database = Environ("Temp") & "\" & CStr(Format(Now, "yyyy-mm-dd_hh-mm-ss.")) _
        & CStr((Timer * 10000) Mod 10000) & CStr(Round(Rnd * 10000, 0)) & ".db"
    Debug.Print Database
    Dim Options As String
    Options = "JournalMode=DELETE;SyncPragma=NORMAL;FKSupport=True;"

    Dim AdoConnStr As String
    AdoConnStr = "Driver=" & Driver & ";" & "Database=" & Database & ";" & Options
    
    Dim SQLQuery As String
    Dim RecordsAffected As Long
    Dim AdoCommand As ADODB.Command
    Set AdoCommand = New ADODB.Command
    With AdoCommand
        .CommandType = adCmdText
        .ActiveConnection = AdoConnStr
        .ActiveConnection.CursorLocation = adUseClient
    End With
    
    '''' ===== Create Functions table ===== ''''
    SQLQuery = Join(Array( _
        "CREATE TABLE functions(", _
        "    name    TEXT COLLATE NOCASE NOT NULL,", _
        "    builtin INTEGER             NOT NULL,", _
        "    type    TEXT COLLATE NOCASE NOT NULL,", _
        "    enc     TEXT COLLATE NOCASE NOT NULL,", _
        "    narg    INTEGER             NOT NULL,", _
        "    flags   INTEGER             NOT NULL", _
        ")" _
    ), vbLf)
    With AdoCommand
        .CommandText = SQLQuery
        .Execute RecordsAffected, Options:=adExecuteNoRecords
    End With
    
    '''' ===== Insert rows into Functions table ===== ''''
    SQLQuery = Join(Array( _
        "INSERT INTO functions", _
        "SELECT * FROM pragma_function_list" _
    ), vbLf)
    With AdoCommand
        .CommandText = SQLQuery
        .Execute RecordsAffected, Options:=adExecuteNoRecords
    End With
    
    '@Ignore StopKeyword
    Stop '''' Lock Db. For example, open in GUI admin tool and start a transaction
    '''' ===== Try changing journal mode ===== ''''
    On Error Resume Next
    With AdoCommand
        .CommandText = "PRAGMA journal_mode = 'WAL'"
        .Execute RecordsAffected, Options:=adExecuteNoRecords
    End With
    If Err.Number <> 0 Then
        Debug.Print "Error: #" & CStr(Err.Number) & ". " & vbNewLine & _
                    "Error description: " & Err.Description
    End If
    On Error GoTo 0
    
    AdoCommand.ActiveConnection.Close
End Sub

ADODB连接和命令有超时设置,默认为30秒。更改此默认值没有明显的效果。实际超时为 100s,这个数字来自 SQLiteODBC 源。驱动程序必须有一个错误。它具有默认超时值,从连接字符串中获取自定义值,但忽略通过 ADODB 库设置的值。所以,添加“Timeout=XXX;”到连接字符串选项就可以了。看起来设置为0意味着无限等待,但是设置为1ms就解决了超时问题。默认情况下关闭的另一个选项 - StepAPI - 应该默认使用。这是另一个驱动程序错误或限制:当启用 StepAPI 时,未设置繁忙处理程序,无论“Timeout=XXX;”如何,超时问题也会消失。选项。