Access 2007, VBA: странная ошибка при вставке BLOB в связанную таблицу - PullRequest
0 голосов
/ 30 января 2020

У меня странная ошибка при попытке вставить двоичный файл в столбец varbinary. Архитектура выглядит следующим образом:

SQL База данных Server 2008 с этим табличным объектом:

CREATE TABLE [dbo].[BLOBs] (
    [FileName] nvarchar(128) NOT NULL
    , [FileExt] AS  CASE
                        WHEN CHARINDEX(N'.', [FileName]) > 0 THEN REVERSE(SUBSTRING(REVERSE([FileName]), 1, CHARINDEX('.', REVERSE([FileName])) - 1))
                        ELSE NULL
                    END PERSISTED
    , [FileBLOB] [varbinary](max) NOT NULL
    , CONSTRAINT [PK_BLOBs] PRIMARY KEY CLUSTERED ( [FileName] ASC ) ON [DEFAULT]
) ON [DEFAULT];
GO

Эта таблица связана с приложением MS Access 2007 как таблица BLOBs, содержащая этот «быстрый» «грязный» письменный модуль:

Public Function saveBLOB(strFQFN As String) As Long
10      If HandleErrors() Then On Error GoTo ERR_HANDLING
20      ErrorHandler().CallStack.PushCallStack "saveBLOB('" & strFQFN & "')"

        Dim db  As DAO.Database
        Dim rs  As DAO.Recordset
        Dim fs  As Long
        Dim fn  As String
        Dim hdl As Integer
        Dim blob()  As Byte

30      fn = Right(strFQFN, Len(strFQFN) - InStrRev(strFQFN, "\"))

        ' read data from file
40      hdl = FreeFile()
50      Open strFQFN For Binary Access Read As #hdl
60      fs = LOF(hdl) - 1
70      ReDim blob(fs)
90      Get #hdl, , blob

        ' updateblob data in database
100     Set db = CurrentDb()
110     Set rs = db.OpenRecordset("BLOBs", dbOpenDynaset, dbSeeChanges)
120     rs.FindFirst ("[FileName] = '" & fn & "'")
130     If rs.NoMatch Then
140         rs.AddNew
150         rs!FileName = fn
160     Else
170         rs.Edit
180     End If

190     rs!FileBLOB = blob
200     rs.Update

210     saveBLOB = True

CLEANUP:
8000    Close #hdl
8010    On Error Resume Next
8020    rs.close
8030    Set rs = Nothing
8040    Set db = Nothing
8050    Erase blob

FINALLY:
9000    On Error GoTo 0
9010    ErrorHandler().CallStack.PopCallStack
9020    Exit Function

ERR_HANDLING:
9900    ErrorHandler().handleError ErrSinkScreen, "saveBLOB()"
9910    saveBLOB = False
9920    Resume CLEANUP
End Function

Кстати: ODB C драйвер SQL Версия сервера 6.01.7601.17514 (SQLSRV32.DLL, 21.11.2010).

Все работает отлично , пока я вызываю функцию через windows:

? saveBLOB("U:\example.txt")
-1

Данные BLOB-объектов успешно сохранены. Теперь есть эта маленькая подпрограмма в форме:

Private Sub UploadFile()
10      If HandleErrors() Then On Error GoTo ERR_HANDLING
20      ErrorHandler().CallStack.PushCallStack Me.Name & ".UploadFile()"

30      If (Not saveBLOB(Nz(Me!txtFQFN, vbNullString))) Then _
            MsgBox "Beim Speichern des BLOBs in der Datenbank ist ein Fehler aufgetreten.", vbExclamation

FINALLY:
9000    ErrorHandler().CallStack.PopCallStack
9010    Exit Sub

ERR_HANDLING:
9900    ErrorHandler().handleError ErrSinkDatabase + ErrSinkScreen, Me.Name & ".UploadFile()"
9910    Resume FINALLY
End Sub

Если здесь вызывается saveBLOB(), возникает ошибка ( Вы пытались присвоить значение Null переменной, которая не является данными Variant тип. ):

Error 3162

ОБНОВЛЕНИЕ : Кажется, это вопрос размера. Вставка недавно созданного файла Excel с 8 КБ работала. Не удалось импортировать файл размером 681 КБ. Столбец BLOB-объекта varbinary(max). Согласно docs.microsoft.com:

max указывает, что максимальный размер хранилища составляет 2 ^ 31-1 байт. Таким образом, 681KB должен идеально вписаться.

Большое спасибо заранее!

1 Ответ

0 голосов
/ 30 января 2020

Существует максимальный размер данных, который вы можете добавить / отредактировать одним оператором. См. Настройка максимального размера текстового реплика. Параметр конфигурации сервера .

Чтобы обойти использование .AppendChunk .

rs!FileBLOB.AppendChunk blob

Для подобных операций на sql сервер, я бы предпочел Adodb, поскольку драйвер OleDb обеспечивает прямое выполнение sql на сервере, а Adodb.Stream упрощает двоичное чтение / запись.

функция saveBLOB с использованием ADODB ( с поздним переплетом):

Public Function saveBLOB(strFQFN As String) As Long

With CreateObject("Scripting.FileSystemObject")  
    Dim fn as String
    fn = .GetFileName(.GetFile(strFQFN))
End With

Dim cnn As Object
Set cnn = CreateObject("ADODB.Connection")
With cnn
    Dim ConString As String
    'uses msoledbsql_18.3 as povider
    ConString = "Provider=MSOLEDBSQL;Data Source=server\instance;Integrated Security=SSPI;Persist Security Info=False;Trusted_Connection=yes;Initial Catalog=db;"
    .Mode = 3 'adModeReadWrite
    .CursorLocation = 3 'adUseClient
    .Open ConString
End With

Dim cmd As Object
Set cmd = CreateObject("ADODB.Command")
With cmd
    .ActiveConnection = cnn
    .CommandText = "SELECT Filename, FileBLOB FROM blob WHERE FiLENAME = ?"
    .Parameters.Append .CreateParameter("FilterFilename", 200, 1, 200, fn)

    With CreateObject("ADODB.Recordset")
        .LockType = 3 'adLockOptimistic
        .Open cmd, , 3 'adOpenDynamic


            Set Stream = CreateObject("ADODB.Stream")
            Stream.Type = 1
            Stream.Open
            Stream.LoadFromFile strFQFN
            If .EOF Then
                .AddNew
                .Fields("Filename") = fn
            End If
            .Fields("FileBLOB").AppendChunk Stream.Read
            .Update
        End If
    End With
End With

saveBLOB = True

Set cmd = Nothing
Set Stream = Nothing
cnn.Close
Set cnn = Nothing
End Function
...