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;”如何,超时问题也会消失。选项。
下面的代码在 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;”如何,超时问题也会消失。选项。