Не секрет, что с помощью хранимых процедур sp_OA... можно создавать в коде экземпляры OLE-объектов, работать с их свойствами, методами, используя в Transact-SQL мощь других языков программирования. Предположим, что нам понадобилось в коде на Transact-SQL решить нетипичную для T-SQL задачу, например изменить дату создания файла. Давайте воспользуемся для решения задачи средствами, например, Visual Basic-а. Итак, создадим в среде разработки на Visual Basic 6.0 новый проект ActiceX dll:
Назовем проект "EdynakFiles", а класс "Attributes":
Приступим к написанию кода на Visual Basic. Исходный код класса Attributes такой:
Класс подготовлен. Теперь его надо скомпилировать (для этого Visual Studio должна быть открыта от имени администратора для возможности редактирования реестра):
После компиляции библиотеки можно наконец приступить к программированию на Transact-SQL. Сперва нам надо создать OLE объект, то есть экземпляр класса, и работать с его методами, ссылаясь на полученный описатель. Для этого используется хранимая процедуры sp_OACreate. В качестве ее первого параметра можно использовать имя библиотеки, соединенное через точку с именем класса:
Кроме этого вместо имени библиотеки и класса, можно было бы использовать guid класса, который прописан в реестре. Его можно найти контекстным поиском:
Тогда код может быть таким:
Назовем проект "EdynakFiles", а класс "Attributes":
Приступим к написанию кода на Visual Basic. Исходный код класса Attributes такой:
'---------------------------------------------------------------------------------------
' Класс "Attributes", позволяет менять некоторые атрибуты файла
'---------------------------------------------------------------------------------------
Option Explicit
'---------------------------------------------------------------------------------------
' Закрытые переменные класса
'---------------------------------------------------------------------------------------
' функции преобразования формата даты
Private Declare
Function SystemTimeToFileTime& Lib "kernel32" (lpSystemTIME As SYSTEMTIME, lpFileTime As FILETIME)
Private Declare
Function FileTimeToSystemTime& Lib "kernel32" (lpFileTime As FILETIME, lpSystemTIME As SYSTEMTIME)
' функции работы с файлами
Private Declare
Function lopen& Lib "kernel32" Alias
"_lopen" (ByVal lpFileName As String, ByVal wReadWhite As Long)
Private Declare
Function lclose& Lib "kernel32" Alias
"_lclose" (ByVal hFile As Long)
Private Declare
Function SetFileTime& Lib "kernel32" (ByVal hFile As Long, lpCreationTime As FILETIME, _
lpLastAccessTime As FILETIME, lpLastWriteTime As FILETIME)
'---------------------------------------------------------------------------------------
' Закрытые типы класса
'---------------------------------------------------------------------------------------
' для хранения даты во внутреннем формате
Private Type
FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
' для хранения даты в системном формате
Private Type
SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
'---------------------------------------------------------------------------------------
' Открытые методы класса
'---------------------------------------------------------------------------------------
Public Function
CreateDateSet(FileName As String, NewDate As Date) As String
Dim SysTime
As SYSTEMTIME, NowTime As FILETIME, handleF As Long, wReadWrite As Long, k As Long
On Error
GoTo ErrorHandler
NewDate =
DateAdd("h", -4, NewDate)
SysTime.wYear = Year(NewDate)
SysTime.wMonth = Month(NewDate)
SysTime.wDay = Day(NewDate)
SysTime.wHour = Hour(NewDate)
SysTime.wMinute = Minute(NewDate)
SysTime.wSecond = Second(NewDate)
' преобразование даты во внутренний формат
k = SystemTimeToFileTime(SysTime, NowTime)
' для изменения атрибута открываем в режиме чтение-запись
wReadWrite =
2
' открываем файл
handleF =
lopen&(FileName, wReadWrite)
' запись нового атрибута
k = SetFileTime&(handleF, NowTime, NowTime, NowTime)
lclose handleF
Exit Function
ExitLabel:
Exit Function
ErrorHandler:
CreateDateSet = "Ошибка в работе метода CreateDateSet. Номер: " & Cstr(VBA.Err.Number) & ". Описание: " & VBA.Err.Description
Resume ExitLabel
End Function
Класс подготовлен. Теперь его надо скомпилировать (для этого Visual Studio должна быть открыта от имени администратора для возможности редактирования реестра):
После компиляции библиотеки можно наконец приступить к программированию на Transact-SQL. Сперва нам надо создать OLE объект, то есть экземпляр класса, и работать с его методами, ссылаясь на полученный описатель. Для этого используется хранимая процедуры sp_OACreate. В качестве ее первого параметра можно использовать имя библиотеки, соединенное через точку с именем класса:
declare @classId
int, @param int
exec @param
= master.dbo.sp_OACreate N'EdynakFiles.Attributes', @classId out
Кроме этого вместо имени библиотеки и класса, можно было бы использовать guid класса, который прописан в реестре. Его можно найти контекстным поиском:
Тогда код может быть таким:
declare @classId int, @param int
exec @param = master.dbo.sp_OACreate N'{52ABE748-1583-4859-9289-CC5C1B3B756E}', @classId out
Для вызова метода воспользуется кодом ниже:
declare @res
varchar ( 8000 ), @FileName varchar ( 255 ) = 'C:\Users\EdynakVV\Desktop\101_20121221.xls',
@NewDate datetime = '2012-12-13 10:14:15'
exec @param
= master.dbo.sp_OAMethod @classId, N'CreateDateSet', @res out, @FileName, @NewDate
select @param
exec @param
= master.dbo.sp_OADestroy @classId
Задача решена, дату создания файла можно менять. Можно создавать свои собственные библиотеки для решения самых разных задач программирования на стороне сервера (не забывая, конечно, о мощи самого языка Transact-SQL). Отмечу, что в производственной среде следует всегда использовать обработку ошибок, при которой вызов sp_OADestroy будет гарантированно выполнен, если экземпляр класса был создан.
Описанная здесь техника, по-видимому не подойдет для работы на компьютерах с 64-х разрядными операционными системами, поскольку в этом случае код библиотеки на Visual Basic 6.0 требуется скомпилировать с помощью компилятора, предназначенного для соответствующих операционных систем. В таком случае можно попробовать создать аналогичные библиотеки с помощью современных версий Visual Studio, например, на языке C#. Постараюсь рассказать об этом в одной из следующих статей.
Комментариев нет:
Отправить комментарий