Использование потоковой передачи файлов SQL Server в Python

Я пытаюсь использовать файловый поток SQL Server 2017 в Python. Вся функциональность, которую я использую, проходит через sqlalchemy, поэтому я пытаюсь найти способ использовать это, поскольку я не нашел никакой реализации в sqlalchemy или других библиотеках (возможно, что-то пропустил, если так, пожалуйста, укажите мне на работающий и проверенная реализация).

Я решил подойти к этому с помощью DLL, основываясь на https://github.com/VisionMark/django-mssql-filestream/blob/master/sql_filestream/win32_streaming_api.py. Однако мой вызов OpenSqlFilestream не удался и возвращает -1 вместо дескриптора файла. Я понятия не имею, в чем проблема или как ее исправить.

from ctypes import c_char, sizeof, windll
from sqlalchemy import create_engine
from sqlalchemy.orm import session_maker
import msvcrt
import os

msodbcsql = windll.LoadLibrary("C:\Windows\System32\msodbcsql17.dll") 

engine = create_engine("mssql+pyodbc://user:pass@test/test?TrustedConnection=yes+driver=ODBC Driver+17+for+SQL+Server")
maker = session_maker(bind=engine)
session = session_maker()
## first query should begind transaction
path = session.execute("SELECT file_stream.PathName() FROM test_filetable").fetchall()[0][0]
## this returns str like "\\\\test\\*"
context = session.execute("SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()").fetchall()[0][0]
## returns bytes

_context = (c_char*len(context)).from_buffer_copy(context)

## This call fails
handle = msodbcsql.OpenSqlFilestream(
        path, # FilestreamPath
        0, # DesiredAccess
        0, # OpenOptions
        _context, # FilestreamTransactionContext
        sizeof(_context), # FilestreamTransactionContextLength
        0 # AllocationSize
    )
## this returns -1 instead of handle

## Never reached, but this should create usable file
desc = msvcrt.open_osfhandle(fsHandle, os.O_RDONLY)
_file = os.fdopen(desc, 'r')

Все запросы работают и выводят (насколько я понимаю) правильные данные.

Как получить файловый доступ к файлу в SQL Server 2017 из python (3.7)?

Редактировать: объекты, которые я читаю, имеют размер в гигабайты, и процессу нужен только потоковый доступ.

1 ответ

Я думаю, что ваша проблема связана с

  1. тот факт, что сеанс SQLAlchemy - это намного больше, чем просто соединение с API БД, и / или
  2. контекст транзакции не подходит для вашего вызова OpenSqlFilestream

Что бы это ни стоило, у меня работает следующее с CPython 3.7.2 и pythonnet 2.4.0:

import clr
clr.AddReference("System.Data")
from System.Data import IsolationLevel
from System.Data.SqlClient import SqlCommand, SqlConnection
from System.Data.SqlTypes import SqlFileStream
from System.IO import File, FileAccess, FileOptions

# adapted from c# code at
# https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/filestream-data
connection_string = r"Data Source=(local)\SQLEXPRESS;Initial Catalog=myDB;Integrated Security=True"
con = SqlConnection(connection_string)
con.Open()
sql = """\
SELECT Photo.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT()
FROM employees WHERE EmployeeID = 1"""
cmd = SqlCommand(sql, con)
tran = con.BeginTransaction(IsolationLevel.ReadCommitted)
cmd.Transaction = tran
rdr = cmd.ExecuteReader()
rdr.Read()
path = rdr.GetString(0)
transaction_context = rdr.GetSqlBytes(1).Buffer
rdr.Close()
allocation_size = 0
input_stream = SqlFileStream(path, transaction_context,
        FileAccess.Read, FileOptions.SequentialScan, allocation_size)
output_stream = File.Create(r"C:\Users\Gord\Desktop\photo.bmp")
input_stream.CopyTo(output_stream)
output_stream.Close()
input_stream.Close()
tran.Commit()
con.Close()
Другие вопросы по тегам