Ошибка: Программе установки SQL Server не удалось получить сведения о системной учетной записи ASPNET

by Alexey Knyazev 31. июля 2010 21:21

При установке SQL Server Express возникает ошибка:

Программе установки SQL Server не удалось получить сведения о системной учетной записи для учетной записи ASPNET. Чтобы продолжить, переустановите платформу .NET Framework, а затем снова запустите программу установки SQL Server.


Английский вариант:
SQL Server Setup failed to obtain system account information for the ASPNET account. To proceed, reinstall the .NET Framework, and then run SQL Server Setup again.


Лекарство:

Запускаем CMD:


cd C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
aspnet_regiis -i

После создания ASPNET-учётной записи, можно повторно запускать установку SQL Server.

Tags: ,

SQL Server

Удобная процедура трассировки событий на стороне сервера

by Alexey Knyazev 23. июля 2010 20:21

SQLTrace Для всех, кто работает с SQL Profiler для отслеживания событий на сервере, хорошо известно, как создавать трассировки. Это не представляет никакой сложности. И действительно, SQL Server Profiler обладает богатым интерфейсом, предназначенным для создания и управления трассировкой, позволяющим анализировать и воспроизводить результаты трассировки.

Но всегда ли есть возможность воспользоваться SQL Profiler`ом!? А самое главное работа Profiler приводит к значительным накладным расходам. Основные затраты идут на создание наборов строк для отправки их клиенту Profiler. В этом плане трассировка с помощью команд T-SQL позволяет минимизировать воздействие на производительность, т.к. она выполняется на стороне сервера и избегает перегрузки.

Кромя того, большинство экспертов по MS SQL Server, в том числе и сотрудники Microsoft рекомендуют отдать предпочтение трассировке на стороне сервера. Это подтверждают и тесты, особый интерес у меня (думаю и у вас) вызвала статья Performance Impact: Profiler Tracing vs. Server Side SQL Tracing.

Разница в замерах чуть ниже, а сейчас скажу о чём собственно это статья и что же это за удобная процедура трассировки: как извесно трассирывание на T-SQL очень трудоёмкая задача и не слишком понятная для начинающих администраторов/разработчиков, поэтому у меня и возникла идея написать что-то более понятное и удобное для повседневного использования.

Ну, а прежде, чем перейти к тексту процедуры покажу, как и обещал, разницу в пропусконой способности SQL Trace и SQL Server Profiler:

Для начала создадим несколько таблиц:

use master
go

--Таблица логов запуска трасс
if ( object_id( N'dbo.Trace_Logs', 'U' ) is not null )
  drop table dbo.Trace_Logs
go
    
create table dbo.Trace_Logs ( id int identity primary key
                            , trace_id int
                            , start_time datetime 
                            , stop_time datetime
                            , tracefile nvarchar(255)
                            , file_size bigint
                            , error int default 0
                            , ret_message nvarchar(1024)
                            , log_time datetime default getdate()
                            , who sysname default suser_sname()
                            )
go      

--Таблица событий
if ( object_id( N'dbo.Trace_Events', 'U' ) is not null )
  drop table dbo.Trace_Events
go

create table dbo.Trace_Events ( EventID int primary key
                              , EventName varchar(50)
                              , DescriptionEng nvarchar(1024)
                              , DescriptionRus nvarchar(1024) 
                              )
go

--Таблица колонок для отслеживания
if ( object_id( N'dbo.Trace_Columns', 'U' ) is not null )
  drop table dbo.Trace_Columns
go

create table dbo.Trace_Columns ( ColumnID int primary key
                               , ColumnName nvarchar(50)
                               , DescriptionEng nvarchar(1024) 
                               , DescriptionRus nvarchar(1024)
                               )
go

Теперь наполним 2 таблицы-справочника данными
1) Сперва справочник событий ( dbo.Trace_Events ):

use master
go

--Заполняем таблицу событий
insert into dbo.Trace_Events 
select 1, 'Reserved', null, null
union all
select 2, 'Reserved', null, null
union all
select 3, 'Reserved', null, null
union all
select 4, 'Reserved', null, null
union all
select 5, 'Reserved', null, null
union all
select 6, 'Reserved', null, null
union all
select 7, 'Reserved', null, null
union all
select 8, 'Reserved', null, null
union all
select 9, 'Reserved', null, null
union all
select 10, 'RPC:Completed', N'Occurs when a remote procedure call (RPC) has completed.'
                          , N'Возникает при завершении удаленного вызова процедуры (RPC).'
union all 
select 11, 'RPC:Starting', N'Occurs when an RPC has started.'
                         , N'Возникает при запуске вызова удаленной процедуры RPC.'
union all 
select 12, 'SQL:BatchCompleted', N'Occurs when a Transact-SQL batch has completed.'
                               , N'Возникает при завершении пакета языка Transact-SQL.'
union all 
select 13, 'SQL:BatchStarting', N'Occurs when a Transact-SQL batch has started.'
                              , N'Возникает при запуске пакета языка Transact-SQL.'
union all 
select 14, 'Audit Login', N'Occurs when a user successfully logs in to SQL Server.'
                        , N'Возникает, когда пользователь успешно входит в систему SQL Server.'
union all 
select 15, 'Audit Logout', N'Occurs when a user logs out of SQL Server.'
                         , N'Возникает, когда пользователь выходит из системы SQL Server.'
union all 
select 16, 'Attention', N'Occurs when attention events, such as client-interrupt requests or broken client connections, happen.'
                      , N'Возникает при событиях, требующих внимания, например запросах клиента на прерывание или разрыв соединения клиента.'
union all 
select 17, 'ExistingConnection', N'Detects all activity by users connected to SQL Server before the trace started.'
                               , N'Обнаруживает всю деятельность пользователей, соединенных с SQL Server до начала трассировки.'
union all 
select 18, 'Audit Server Starts and Stops', N'Occurs when the SQL Server service state is modified.'
                                          , N'Возникает при изменении состояния службы SQL Server.'
union all 
select 19, 'DTCTransaction', N'Tracks Microsoft Distributed Transaction Coordinator (MS DTC) coordinated transactions between two or more databases.'
                           , N'Отслеживает согласованные транзакции координатора распределенных транзакций Майкрософт (MS DTC) между двумя или более базами данных.'
union all 
select 20, 'Audit Login Failed', N'Indicates that a login attempt to SQL Server from a client failed.'
                               , N'Показывает, что попытка входа клиента в систему SQL Server завершилась неудачно.'
union all 
select 21, 'EventLog', N'Indicates that events have been logged in the Windows application log.'
                     , N'Показывает, что события были записаны в журнал приложений Windows.'
union all 
select 22, 'ErrorLog', N'Indicates that error events have been logged in the SQL Server error log.'
           , N'Показывает, что связанные с ошибками события были записаны в журнал ошибок сервера SQL Server.'
union all 
select 23, 'Lock:Released', N'Indicates that a lock on a resource, such as a page, has been released.'
                          , N'Указывает, что была снята блокировка ресурса, например страницы.'
union all 
select 24, 'Lock:Acquired', N'Indicates acquisition of a lock on a resource, such as a data page.'
                          , N'Указывает, что была установлена блокировка ресурса, например страницы данных.'
union all 
select 25, 'Lock:Deadlock', N'Indicates that two concurrent transactions have deadlocked each other by trying to obtain incompatible locks on resources the other transaction owns.'
                          , N'Указывает, что две одновременно выполняемые транзакции взаимно блокируют друг друга, пытаясь установить несовместимые блокировки ресурсов, принадлежащих другой транзакции.'
union all 
select 26, 'Lock:Cancel', N'Indicates that the acquisition of a lock on a resource has been canceled (for example, due to a deadlock).'
                        , N'Показывает, что запрос на блокировку ресурса был отменен (например, из-за взаимоблокировки).'
union all 
select 27, 'Lock:Timeout', N'Indicates that a request for a lock on a resource, such as a page, has timed out due to another transaction holding a blocking lock on the required resource. Time-out is determined by the @@LOCK_TIMEOUT function, and can be set with the SET LOCK_TIMEOUT statement.'
                         , N'Показывает, что запрос на блокировку некоторого ресурса, например страницы, превысил время ожидания, поскольку данный ресурс был блокирован другой транзакцией. Время ожидания определяется функцией @@LOCK_TIMEOUT и может устанавливаться инструкцией SET LOCK_TIMEOUT.'
union all 
select 28, 'Degree of Parallelism Event (7.0 Insert)', N'Occurs before a SELECT, INSERT, or UPDATE statement is executed.'
                                                     , N'Возникает перед выполнением инструкций SELECT, INSERT и UPDATE.'
union all 
select 29, 'Reserved', N'Use Event 28 instead.'
                     , N'Вместо него используется событие 28.'
union all 
select 30, 'Reserved', N'Use Event 28 instead.'
                     , N'Вместо него используется событие 28.'
union all 
select 31, 'Reserved', N'Use Event 28 instead.'
                     , N'Вместо него используется событие 28.'
union all 
select 32, 'Reserved', N'Reserved'
                     , N'Зарезервировано.'
union all 
select 33, 'Exception', N'Indicates that an exception has occurred in SQL Server.'
                      , N'Указывает, что в сервере SQL Server произошло исключение.'
union all 
select 34, 'SP:CacheMiss', N'Indicates when a stored procedure is not found in the procedure cache.'
                         , N'Указывает, что хранимая процедура не найдена в процедурном кэше.'
union all 
select 35, 'SP:CacheInsert', N'Indicates when an item is inserted into the procedure cache.'
                           , N'Указывает, что элемент вставлен в процедурный кэш.'
union all 
select 36, 'SP:CacheRemove', N'Indicates when an item is removed from the procedure cache.'
                           , N'Указывает, что элемент удален из процедурного кэша.'
union all 
select 37, 'SP:Recompile', N'Indicates that a stored procedure was recompiled.'
                         , N'Указывает, что была выполнена повторная компиляция хранимой процедуры.'
union all 
select 38, 'SP:CacheHit', N'Indicates when a stored procedure is found in the procedure cache.'
                        , N'Указывает, что хранимая процедура найдена в процедурном кэше.'
union all 
select 39, 'Deprecated', N'Deprecated'
                       , N'Устарело.'
union all 
select 40, 'SQL:StmtStarting', N'Occurs when the Transact-SQL statement has started.'
                             , N'Возникает при запуске инструкции Transact-SQL.'
union all 
select 41, 'SQL:StmtCompleted', N'Occurs when the Transact-SQL statement has completed.'
                              , N'Возникает при завершении инструкции Transact-SQL.'
union all 
select 42, 'SP:Starting', N'Indicates when the stored procedure has started.'
                        , N'Указывает, что запущена хранимая процедура.'
union all 
select 43, 'SP:Completed', N'Indicates when the stored procedure has completed.'
                         , N'Указывает, что выполнение хранимой процедуры завершено.'
union all 
select 44, 'SP:StmtStarting', N'Indicates that a Transact-SQL statement within a stored procedure has started executing.'
                            , N'Указывает, что в хранимой процедуре начато выполнение инструкции Transact-SQL.'
union all 
select 45, 'SP:StmtCompleted', N'Indicates that a Transact-SQL statement within a stored procedure has finished executing.'
                             , N'Указывает, что выполнение инструкции Transact-SQL в хранимой процедуре завершено.'
union all 
select 46, 'Object:Created', N'Indicates that an object has been created, such as for CREATE INDEX, CREATE TABLE, and CREATE DATABASE statements.'
                           , N'Указывает на создание объекта, например с помощью инструкций CREATE INDEX, CREATE TABLE или CREATE DATABASE.'
union all 
select 47, 'Object:Deleted', N'Indicates that an object has been deleted, such as in DROP INDEX and DROP TABLE statements.'
                           , N'Указывает на удаление объекта, например с помощью инструкций DROP INDEX или DROP TABLE.'
union all 
select 48, 'Reserved', N'', N''
union all 
select 49, 'Reserved', N'', N''
union all 
select 50, 'SQL Transaction', N'Tracks Transact-SQL BEGIN, COMMIT, SAVE, and ROLLBACK TRANSACTION statements.'
                            , N'Отслеживает инструкции языка Transact-SQL BEGIN, COMMIT, SAVE и ROLLBACK TRANSACTION.'
union all 
select 51, 'Scan:Started', N'Indicates when a table or index scan has started.'
                         , N'Указывает, что был начат просмотр таблицы или индекса.'
union all 
select 52, 'Scan:Stopped', N'Indicates when a table or index scan has stopped.'
                         , N'Указывает, что просмотр таблицы или индекса завершилось.'
union all 
select 53, 'CursorOpen', N'Indicates when a cursor is opened on a Transact-SQL statement by ODBC, OLE DB, or DB-Library.'
                       , N'Указывает, что в инструкции Transact-SQL с помощью API-функций ODBC, OLE DB или DB-Library был открыт курсор.'
union all 
select 54, 'TransactionLog', N'Tracks when transactions are written to the transaction log.'
                           , N'Следит за записью транзакций в журнал транзакций.'
union all 
select 55, 'Hash Warning', N'Indicates that a hashing operation (for example, hash join, hash aggregate, hash union, and hash distinct) that is not processing on a buffer partition has reverted to an alternate plan. This can occur because of recursion depth, data skew, trace flags, or bit counting.'
                         , N'Указывает, что операция хэширования (например, Hash Join, Hash Aggregate, Hash Union и Hash Distinct), которая не выполняется в буферной секции, обратилась к альтернативному плану. Это может происходить из-за глубины рекурсии, неравномерного смещения данных, флагов трассировки или подсчета битов.'
union all 
select 56, 'Reserved', N'', N''
union all 
select 57, 'Reserved', N'', N''
union all 
select 58, 'Auto Stats', N'Indicates an automatic updating of index statistics has occurred.'
                       , N'Указывает, что произошло автоматическое обновление статистики индекса.'
union all 
select 59, 'Lock:Deadlock Chain', N'Produced for each of the events leading up to the deadlock.'
                                , N'Создается для каждого события, приводящего к взаимоблокировке.'
union all 
select 60, 'Lock:Escalation', N'Indicates that a finer-grained lock has been converted to a coarser-grained lock (for example, a page lock escalated or converted to a TABLE or HoBT lock).'
                            , N'Указывает, что блокировка более мелких фрагментов данных была преобразована в блокировку более крупных фрагментов данных (например, блокировка страницы была укрупнена или преобразована в блокировку таблицы или блокировку HoBT).'
union all 
select 61, 'OLE DB Errors', N'Indicates that an OLE DB error has occurred.'
                          , N'Показывает, что произошла ошибка OLE DB.'
union all 
select 62, 'Reserved', N'', N''
union all 
select 63, 'Reserved', N'', N''
union all 
select 64, 'Reserved', N'', N''
union all 
select 65, 'Reserved', N'', N''
union all 
select 66, 'Reserved', N'', N''
union all 
select 67, 'Execution Warnings', N'Indicates any warnings that occurred during the execution of a SQL Server statement or stored procedure.'
                               , N'Показывает все предупреждения, которые были выданы за время выполнения инструкции или хранимой процедуры SQL Server.'
union all 
select 68, 'Showplan Text (Unencoded)', N'Displays the plan tree of the Transact-SQL statement executed.'
                                      , N'Показывает дерево плана выполнения для текущей инструкции Transact-SQL.'
union all 
select 69, 'Sort Warnings', N'"Indicates sort operations that do not fit into memory. Does not include sort operations involving the creating of indexes; only sort operations within a query (such as an ORDER BY clause used in a SELECT statement)."'
                          , N'Показывает операции сортировки, которые не помещаются в памяти. Сюда не входят операции сортировки, предполагающие создание индексов, а только операции сортировки в запросе (например, предложение ORDER BY инструкции SELECT).'
union all 
select 70, 'CursorPrepare', N'Indicates when a cursor on a Transact-SQL statement is prepared for use by ODBC, OLE DB, or DB-Library.'
                          , N'Показывает, что курсор в инструкции Transact-SQL подготовлен для использования API-функциями ODBC, OLE DB или DB-Library.'
union all 
select 71, 'Prepare SQL', N'ODBC, OLE DB, or DB-Library has prepared a Transact-SQL statement or statements for use.'
                        , N'API-функции ODBC, OLE DB или DB-Library подготовили одну или несколько инструкций Transact-SQL для использования.'
union all 
select 72, 'Exec Prepared SQL', N'ODBC, OLE DB, or DB-Library has executed a prepared Transact-SQL statement or statements.'
                              , N'API-функции ODBC, OLE DB или DB-Library выполнили одну или несколько инструкций Transact-SQL.'
union all 
select 73, 'Unprepare SQL', N'ODBC, OLE DB, or DB-Library has unprepared (deleted) a prepared Transact-SQL statement or statements.'
                          , N'API-функции ODBC, OLE DB или DB-Library отменили готовность (удалили) одной или нескольких подготовленных инструкций Transact-SQL.'
union all 
select 74, 'CursorExecute', N'A cursor previously prepared on a Transact-SQL statement by ODBC, OLE DB, or DB-Library is executed.'
                          , N'Выполнен курсор, подготовленный в инструкции Transact-SQL с помощью API-функций ODBC, OLE DB или DB-Library.'
union all 
select 75, 'CursorRecompile', N'A cursor opened on a Transact-SQL statement by ODBC or DB-Library has been recompiled either directly or due to a schema change. Triggered for ANSI and non-ANSI cursors.'
                            , N'Курсор, открытый в инструкции Transact-SQL с помощью API-функций ODBC или DB-Library, был повторно скомпилирован явным образом или вследствие изменения схемы. Срабатывает как для курсоров ANSI, так и для курсоров, не являющихся курсорами ANSI.'
union all 
select 76, 'CursorImplicitConversion', N'A cursor on a Transact-SQL statement is converted by SQL Server from one type to another. Triggered for ANSI and non-ANSI cursors.'
                                     , N'Курсор в инструкции Transact-SQL преобразуется SQL Server из одного типа в другой. Срабатывает как для курсоров ANSI, так и для курсоров, не являющихся курсорами ANSI.'
union all 
select 77, 'CursorUnprepare', N'A prepared cursor on a Transact-SQL statement is unprepared (deleted) by ODBC, OLE DB, or DB-Library.'
                            , N'API -функции ODBC, OLE DB или DB-Library отменяют готовность курсора (удаляют), подготовленного в инструкции Transact-SQL.'
union all 
select 78, 'CursorClose', N'A cursor previously opened on a Transact-SQL statement by ODBC, OLE DB, or DB-Library is closed.'
                        , N'Закрыт курсор, предварительно открытый в инструкции Transact-SQL с помощью API-функций ODBC, OLE DB или DB-Library.'
union all 
select 79, 'Missing Column Statistics', N'Column statistics that could have been useful for the optimizer are not available.'
                                      , N'Недоступны статистические данные столбцов, которые были бы полезны оптимизатору.'
union all 
select 80, 'Missing Join Predicate', N'Query that has no join predicate is being executed. This could result in a long-running query.'
                                   , N'Выполняется запрос, не имеющий предиката соединения. Это может привести к длительному выполнению запроса.'
union all 
select 81, 'Server Memory Change', N'SQL Server memory usage has increased or decreased by either 1 megabyte (MB) or 5 percent of the maximum server memory, whichever is greater.'
                                 , N'Объем памяти, используемый SQL Server, увеличился или уменьшился на 1 мегабайт (МБ) либо на 5% от максимального объема памяти, в зависимости от того, какая величина больше.'
union all 
select 82, 'User Configurable (0-9)', N'Event data defined by the user.'
                                    , N'Данные событий, определяемые пользователем.'
union all 
select 83, 'User Configurable (0-9)', N'Event data defined by the user.'
                                      , N'Данные событий, определяемые пользователем.'
union all 
select 84, 'User Configurable (0-9)', N'Event data defined by the user.'
                                    , N'Данные событий, определяемые пользователем.'
union all 
select 85, 'User Configurable (0-9)', N'Event data defined by the user.'
                                    , N'Данные событий, определяемые пользователем.'
union all 
select 86, 'User Configurable (0-9)', N'Event data defined by the user.'
                                      , N'Данные событий, определяемые пользователем.'
union all 
select 87, 'User Configurable (0-9)', N'Event data defined by the user.'
                                    , N'Данные событий, определяемые пользователем.'
union all 
select 88, 'User Configurable (0-9)', N'Event data defined by the user.'
                                    , N'Данные событий, определяемые пользователем.'
union all 
select 89, 'User Configurable (0-9)', N'Event data defined by the user.'
                                      , N'Данные событий, определяемые пользователем.'
union all 
select 90, 'User Configurable (0-9)', N'Event data defined by the user.'
                                    , N'Данные событий, определяемые пользователем.'
union all 
select 91, 'User Configurable (0-9)', N'Event data defined by the user.'
                                    , N'Данные событий, определяемые пользователем.'
union all 
select 92, 'Data File Auto Grow', N'Indicates that a data file was extended automatically by the server.'
                                , N'Указывает, что сервер автоматически увеличил файл данных.'
union all 
select 93, 'Log File Auto Grow', N'Indicates that a log file was extended automatically by the server.'
                               , N'Указывает, что сервер автоматически расширил файл журнала.'
union all 
select 94, 'Data File Auto Shrink', N'Indicates that a data file was shrunk automatically by the server.'
                                    , N'Указывает, что сервер автоматически сжал файл данных.'
union all 
select 95, 'Log File Auto Shrink', N'Indicates that a log file was shrunk automatically by the server.'
                                 , N'Указывает, что сервер автоматически сжал файл журнала.'
union all 
select 96, 'Showplan Text', N'Displays the query plan tree of the SQL statement from the query optimizer. Note that the TextData column does not contain the Showplan for this event.'
                          , N'Показывает дерево плана запроса для инструкции SQL из оптимизатора запросов. Обратите внимание, что столбец TextData не содержит инструкцию Showplan для данного сообщения.'
union all 
select 97, 'Showplan All', N'Displays the query plan with full compile-time details of the SQL statement executed. Note that the TextData column does not contain the Showplan for this event.'
                         , N'Выводит план запроса со всеми подробностями процесса компиляции для выполненной инструкции SQL. Обратите внимание, что столбец TextData не содержит инструкцию Showplan для данного сообщения.'
union all 
select 98, 'Showplan Statistics Profile', N'Displays the query plan with full run-time details of the SQL statement executed. Note that the TextData column does not contain the Showplan for this event.'
                                        , N'Выводит план запроса со всеми подробностями времени выполнения для выполненной инструкции SQL. Обратите внимание, что столбец TextData не содержит инструкцию Showplan для данного сообщения.'
union all 
select 99, 'Reserved', N'', N''
union all 
select 100, 'RPC Output Parameter', N'Produces output values of the parameters for every RPC.'
                                  , N'Выводит выходные значения параметров для каждого вызова RPC.'
union all 
select 101, 'Reserved', N'', N''
union all 
select 102, 'Audit Statement GDR Event', N'Occurs every time a GRANT, DENY, REVOKE for a statement permission is issued by any user in SQL Server.'
                                       , N'Возникает каждый раз, когда пользователь SQL Server выдает разрешения GRANT, DENY, REVOKE на инструкции.'
union all 
select 103, 'Audit Object GDR Event', N'Occurs every time a GRANT, DENY, REVOKE for an object permission is issued by any user in SQL Server.'
                                    , N'Возникает каждый раз, когда пользователь SQL Server выдает разрешения GRANT, DENY, REVOKE на объект.'
union all 
select 104, 'Audit AddLogin Event', N'"Occurs when a SQL Server login is added or removed; for sp_addlogin and sp_droplogin."'
                                  , N'Возникает, когда добавляется или удаляется имя входа SQL Server. Для хранимых процедур sp_addlogin и sp_droplogin.'
union all 
select 105, 'Audit Login GDR Event', N'"Occurs when a Windows login right is added or removed; for sp_grantlogin, sp_revokelogin, and sp_denylogin."'
                                   , N'Происходит, когда добавляется или удаляется право входа в систему Windows. Для хранимых процедур sp_grantlogin, sp_revokelogin и sp_denylogin.'
union all 
select 106, 'Audit Login Change Property Event', N'"Occurs when a property of a login, except passwords, is modified; for sp_defaultdb and sp_defaultlanguage."'
                                               , N'Возникает при изменении свойств имени входа, за исключением пароля. Для хранимых процедур sp_defaultdb и sp_defaultlanguage.'
union all 
select 107, 'Audit Login Change Password Event', N'Occurs when a SQL Server login password is changed. Passwords are not recorded.'
                                               , N'Возникает при изменении пароля имени входа SQL Server. Пароли не записываются.'
union all 
select 108, 'Audit Add Login to Server Role Event', N'"Occurs when a login is added or removed from a fixed server role; for sp_addsrvrolemember, and sp_dropsrvrolemember."'
                                                    , N'Возникает при изменении или удалении имени входа из предопределенной роли сервера. Для хранимых процедур sp_addsrvrolemember и sp_dropsrvrolemember.'
union all 
select 109, 'Audit Add DB User Event', N'"Occurs when a login is added or removed as a database user (Windows or SQL Server) to a database; for sp_grantdbaccess, sp_revokedbaccess, sp_adduser, and sp_dropuser."'
                                     , N'Возникает при добавлении или удалении из базы данных имени входа пользователя базы данных (Windows или SQL Server). Для хранимых процедур sp_grantdbaccess, sp_revokedbaccess, sp_adduser и sp_dropuser.'
union all 
select 110, 'Audit Add Member to DB Role Event', N'"Occurs when a login is added or removed as a database user (fixed or user-defined) to a database; for sp_addrolemember, sp_droprolemember, and sp_changegroup."'
                                               , N'Возникает при добавлении или удалении из базы данных имени входа пользователя базы данных (встроенного или пользовательского). Для хранимых процедур sp_addrolemember, sp_droprolemember и sp_changegroup.'
union all 
select 111, 'Audit Add Role Event', N'"Occurs when a login is added or removed as a database user to a database; for sp_addrole and sp_droprole."'
                                  , N'Возникает при изменении или удалении из базы данных имени входа пользователя базы данных. Для хранимых процедур sp_addrole и sp_droprole.'
union all 
select 112, 'Audit App Role Change Password Event', N'Occurs when a password of an application role is changed.'
                                                    , N'Возникает при изменении пароля роли приложения.'
union all 
select 113, 'Audit Statement Permission Event', N'Occurs when a statement permission (such as CREATE TABLE) is used.'
                                              , N'Возникает при использовании разрешения инструкции (например, CREATE TABLE).'
union all 
select 114, 'Audit Schema Object Access Event', N'Occurs when an object permission (such as SELECT) is used, both successfully or unsuccessfully.'
                                              , N'Возникает при использовании объектного разрешения (например, SELECT), как успешном, так и неуспешном.'
union all 
select 115, 'Audit Backup/Restore Event', N'Occurs when a BACKUP or RESTORE command is issued.'
                                        , N'Возникает при выполнении команды BACKUP или RESTORE.'
union all 
select 116, 'Audit DBCC Event', N'Occurs when DBCC commands are issued.'
                              , N'Возникает при выполнении консольной команды.'
union all 
select 117, 'Audit Change Audit Event', N'Occurs when audit trace modifications are made.'
                                      , N'Возникает при изменениях трассировки аудита.'
union all 
select 118, 'Audit Object Derived Permission Event', N'Occurs when a CREATE, ALTER, and DROP object commands are issued.'
                                                   , N'Возникает при выполнении команд CREATE, ALTER и DROP в отношении объектов.'
union all 
select 119, 'OLEDB Call Event', N'Occurs when OLE DB provider calls are made for distributed queries and remote stored procedures.'
                              , N'Возникает, когда поставщик OLE DB вызывает распределенные запросы и удаленные хранимые процедуры.'
union all 
select 120, 'OLEDB QueryInterface Event', N'Occurs when OLE DB QueryInterface calls are made for distributed queries and remote stored procedures.'
                                        , N'Возникает, когда интерфейс OLE DB QueryInterface вызывает распределенные запросы и удаленные хранимые процедуры.'
union all 
select 121, 'OLEDB DataRead Event', N'Occurs when a data request call is made to the OLE DB provider.'
                                  , N'Возникает при вызове запроса данных к поставщику OLE DB.'
union all 
select 122, 'Showplan XML', N'Occurs when an SQL statement executes. Include this event to identify Showplan operators. Each event is stored in a well-formed XML document. Note that the Binary column for this event contains the encoded Showplan. Use SQL Server Profiler to open the trace and view the Showplan.'
                          , N'Возникает при выполнении инструкции SQL. Включите это событие для идентификации операторов Showplan. Каждое событие хранится в правильно оформленном XML-документе. Обратите внимание, что столбец Binary для данного сообщения содержит закодированную инструкцию Showplan. Для просмотра инструкции Showplan откройте трассировку в приложении SQL Server Profiler.'
union all 
select 123, 'SQL:FullTextQuery', N'Occurs when a full text query executes.'
                               , N'Возникает при выполнении полнотекстового запроса.'
union all 
select 124, 'Broker:Conversation', N'Reports the progress of a Service Broker conversation.'
                                 , N'Сообщает о состоянии диалога компонента Service Broker.'
union all 
select 125, 'Deprecation Announcement', N'Occurs when you use a feature that will be removed from a future version of SQL Server.'
                                      , N'Возникает при использовании возможности, которая будет удалена из будущей версии SQL Server.'
union all 
select 126, 'Deprecation Final Support', N'Occurs when you use a feature that will be removed from the next major release of SQL Server.'
                                       , N'Возникает при использовании возможности, которая будет удалена из следующего основного выпуска SQL Server.'
union all 
select 127, 'Exchange Spill Event', N'Occurs when communication buffers in a parallel query plan have been temporarily written to the tempdb database.'
                                  , N'Возникает, когда буферы связи в плане параллельного запроса были временно записаны в базу данных tempdb.'
union all 
select 128, 'Audit Database Management Event', N'Occurs when a database is created, altered, or dropped.'
                                             , N'Возникает при создании, изменении и удалении базы данных.'
union all 
select 129, 'Audit Database Object Management Event', N'Occurs when a CREATE, ALTER, or DROP statement executes on database objects, such as schemas.'
                                                    , N'Возникает при выполнении инструкций CREATE, ALTER или DROP в отношении таких объектов базы данных, как схема.'
union all 
select 130, 'Audit Database Principal Management Event', N'Occurs when principals, such as users, are created, altered, or dropped from a database.'
                                                       , N'Возникает при создании, изменении или удалении из базы данных таких участников, как пользователь.'
union all 
select 131, 'Audit Schema Object Management Event', N'Occurs when server objects are created, altered, or dropped.'
                                                  , N'Возникает при создании, изменении и удалении серверных объектов.'
union all 
select 132, 'Audit Server Principal Impersonation Event', N'Occurs when there is an impersonation within server scope, such as EXECUTE AS LOGIN.'
                                                        , N'Возникает при наличии в области действия сервера олицетворения, например EXECUTE AS LOGIN.'
union all 
select 133, 'Audit Database Principal Impersonation Event', N'Occurs when an impersonation occurs within the database scope, such as EXECUTE AS USER or SETUSER.'
                                                          , N'Возникает при наличии в области действия базы данных олицетворения, например EXECUTE AS USER или SETUSER.'
union all 
select 134, 'Audit Server Object Take Ownership Event', N'Occurs when the owner is changed for objects in server scope.'
                                                      , N'Возникает при изменении владельца объектов в области действия сервера.'
union all 
select 135, 'Audit Database Object Take Ownership Event', N'Occurs when a change of owner for objects within database scope occurs.'
                                                        , N'Возникает при изменении владельца объектов в области действия базы данных.'
union all 
select 136, 'Broker:Conversation Group', N'Occurs when Service Broker creates a new conversation group or drops an existing conversation group.'
                                       , N'Происходит, когда компонент Service Broker создает новую группу сообщений или удаляет существующую.'
union all 
select 137, 'Blocked Process Report', N'Occurs when a process has been blocked for more than a specified amount of time. Does not include system processes or processes that are waiting on non deadlock-detectable resources. Use sp_configure to configure the threshold and frequency at which reports are generated.'
                                    , N'Возникает, если процесс блокирован дольше, чем указанное время. Не включает системные процессы или процессы, ожидающие ресурсы, для которых невозможно определить состояние взаимоблокировки. Для настройки порога и частоты формирования отчетов используйте хранимую процедуру sp_configure.'
union all 
select 138, 'Broker:Connection', N'Reports the status of a transport connection managed by Service Broker.'
                               , N'Сообщает о состоянии транспортного соединения, управляемого компонентом Service Broker.'
union all 
select 139, 'Broker:Forwarded Message Sent', N'Occurs when Service Broker forwards a message.'
                                           , N'Происходит, когда компонент Service Broker перенаправляет сообщение.'
union all 
select 140, 'Broker:Forwarded Message Dropped', N'Occurs when Service Broker drops a message that was intended to be forwarded.'
                                              , N'Происходит, когда компонент Service Broker удаляет сообщение, предназначенное для перенаправления.'
union all 
select 141, 'Broker:Message Classify', N'Occurs when Service Broker determines the routing for a message.'
                                     , N'Возникает при определении компонентом Service Broker маршрута сообщения.'
union all 
select 142, 'Broker:Transmission', N'Indicates that errors have occurred in the Service Broker transport layer. The error number and state values indicate the source of the error.'
                                 , N'Показывает, что в транспортном уровне компонента Service Broker возникла ошибка. На источник ошибки указывает ее номер и значения состояния.'
union all 
select 143, 'Broker:Queue Disabled', N'Indicates a poison message was detected because there were five consecutive transaction rollbacks on a Service Broker queue. The event contains the database ID and queue ID of the queue that contains the poison message.'
                                   , N'Указывает, что было обнаружено опасное сообщение, поскольку в очереди компонента Service Broker произошло пять последовательных откатов транзакций. Это событие содержит идентификаторы базы данных и очереди, в которой находится опасное сообщение.'
union all 
select 144, 'Reserved', N'', N''
union all 
select 145, 'Reserved', N'', N''
union all 
select 146, 'Showplan XML Statistics Profile', N'Occurs when an SQL statement executes. Identifies the Showplan operators and displays complete, compile-time data. Note that the Binary column for this event contains the encoded Showplan. Use SQL Server Profiler to open the trace and view the Showplan.'
                                             , N'Возникает при выполнении инструкции SQL. Идентифицирует операторы Showplan и выводит все данные процесса компиляции. Обратите внимание, что столбец Binary для данного сообщения содержит закодированную инструкцию Showplan. Для просмотра инструкции Showplan откройте трассировку в приложении SQL Server Profiler.'
union all 
select 148, 'Deadlock Graph', N'Occurs when an attempt to acquire a lock is canceled because the attempt was part of a deadlock and was chosen as the deadlock victim. Provides an XML description of a deadlock.'
                            , N'Возникает в том случае, если попытка получить блокировку отменяется потому, что эта попытка была частью взаимоблокировки и была выбрана в качестве жертвы. Предоставляет описание взаимоблокировки в формате XML.'
union all 
select 149, 'Broker:Remote Message Acknowledgement', N'Occurs when Service Broker sends or receives a message acknowledgement.'
                                                   , N'Возникает при отправке или получении компонентом Service Broker подтверждения сообщения.'
union all 
select 150, 'Trace File Close', N'Occurs when a trace file closes during rollback.'
                              , N'Происходит при закрытии файла трассировки во время операции переключения на файл продолжения.'
union all 
select 151, 'Reserved', N'', N''
union all 
select 152, 'Audit Change Database Owner', N'Occurs when ALTER AUTHORIZATION is used to change the owner of a database and permissions are checked to do that.'
                                         , N'Возникает при использовании инструкции ALTER AUTHORIZATION для изменения владельца базы данных и проверке разрешений на это действие.'
union all 
select 153, 'Audit Schema Object Take Ownership Event', N'Occurs when ALTER AUTHORIZATION is used to assign an owner to an object and permissions are checked to do that.'
                                                      , N'Возникает при использовании инструкции ALTER AUTHORIZATION для присвоения владельца объекту и проверке разрешений на это действие.'
union all 
select 154, 'Reserved', N'', N''
union all 
select 155, 'FT:Crawl Started', N'Occurs when a full-text crawl (population) starts. Use to check if a crawl request is picked up by worker tasks.'
                              , N'Возникает при запуске полнотекстового сканирования (заполнения). Используется для проверки, принят ли сканирующий запрос задачами-исполнителями.'
union all 
select 156, 'FT:Crawl Stopped', N'Occurs when a full-text crawl (population) stops. Stops occur when a crawl completes successfully or when a fatal error occurs.'
                              , N'Возникает при остановке полнотекстового сканирования (заполнения). Остановка происходит при успешном завершении сканирования или возникновении неустранимой ошибки.'
union all 
select 157, 'FT:Crawl Aborted', N'Occurs when an exception is encountered during a full-text crawl. Usually causes the full-text crawl to stop.'
                              , N'Возникает при обнаружении исключения во время полнотекстового сканирования. Обычно приводит к остановке полнотекстового сканирования.'
union all 
select 158, 'Audit Broker Conversation', N'Reports audit messages related to Service Broker dialog security.'
                                       , N'Уведомляет о сообщениях аудита, связанных с безопасностью диалога компонента Service Broker.'
union all 
select 159, 'Audit Broker Login', N'Reports audit messages related to Service Broker transport security.'
                                , N'Уведомляет о сообщениях аудита, связанных с безопасностью транспорта компонента Service Broker.'
union all 
select 160, 'Broker:Message Undeliverable', N'Occurs when Service Broker is unable to retain a received message that should have been delivered to a service.'
                                          , N'Возникает, если компоненту Service Broker не удается получить сообщение, которое должно быть доставлено службе.'
union all 
select 161, 'Broker:Corrupted Message', N'Occurs when Service Broker receives a corrupted message.'
                                      , N'Происходит, когда компонент Service Broker получает поврежденное сообщение.'
union all 
select 162, 'User Error Message', N'Displays error messages that users see in the case of an error or exception.'
                                , N'Выводит сообщения об ошибках, которые пользователь видит в случае ошибки или исключения.'
union all 
select 163, 'Broker:Activation', N'Occurs when a queue monitor starts an activation stored procedure, sends a QUEUE_ACTIVATION notification, or when an activation stored procedure started by a queue monitor exits.'
                               , N'Возникает, если монитор очереди запускает хранимую процедуру активации, отправляет уведомление QUEUE_ACTIVATION или по завершению хранимой процедуры активации, запущенной монитором очереди.'
union all 
select 164, 'Object:Altered', N'Occurs when a database object is altered.'
                            , N'Возникает при изменении объекта базы данных.'
union all 
select 165, 'Performance statistics', N'Occurs when a compiled query plan has been cached for the first time, recompiled, or removed from the plan cache.'
                                    , N'Возникает, если скомпилированный план запроса кэшируется впервые, повторно компилируется или удаляется из кэша плана.'
union all 
select 166, 'SQL:StmtRecompile', N'Occurs when a statement-level recompilation occurs.'
                               , N'Возникает при повторной компиляции на уровне инструкции.'
union all 
select 167, 'Database Mirroring State Change', N'Occurs when the state of a mirrored database changes.'
                                             , N'Возникает при изменении состояния зеркальной базы данных.'
union all 
select 168, 'Showplan XML For Query Compile', N'Occurs when an SQL statement compiles. Displays the complete, compile-time data. Note that the Binary column for this event contains the encoded Showplan. Use SQL Server Profiler to open the trace and view the Showplan.'
                                            , N'Возникает при компиляции инструкции SQL. Выводит все данные процесса компиляции. Обратите внимание, что столбец Binary для данного сообщения содержит закодированную инструкцию Showplan. Для просмотра инструкции Showplan откройте трассировку в приложении SQL Server Profiler.'
union all 
select 169, 'Showplan All For Query Compile', N'Occurs when an SQL statement compiles. Displays complete, compile-time data. Use to identify Showplan operators.'
                                            , N'Возникает при компиляции инструкции SQL. Выводит все данные процесса компиляции. Используется для идентификации операторов Showplan.'
union all 
select 170, 'Audit Server Scope GDR Event', N'Indicates that a grant, deny, or revoke event for permissions in server scope occurred, such as creating a login.'
                                          , N'Указывает, что возникло событие «предоставления», «запрещения» или «отмены» для разрешений в области действия сервера, например такое, как создание имени входа.'
union all 
select 171, 'Audit Server Object GDR Event', N'Indicates that a grant, deny, or revoke event for a schema object, such as a table or function, occurred.'
                                           , N'Указывает, что возникло событие «предоставления», «запрещения» или «отмены» разрешения для объекта схемы, например для таблицы или функции.'
union all 
select 172, 'Audit Database Object GDR Event', N'Indicates that a grant, deny, or revoke event for database objects, such as assemblies and schemas, occurred.'
                                             , N'Указывает, что возникло событие «предоставления», «запрещения» или «отмены» разрешения для объектов базы данных, например для сборки или схемы.'
union all 
select 173, 'Audit Server Operation Event', N'Occurs when Security Audit operations such as altering settings, resources, external access, or authorization are used.'
                                          , N'Возникает при использовании таких операций аудита безопасности, как изменение параметров, ресурсов, внешнего доступа или проверки подлинности.'
union all 
select 175, 'Audit Server Alter Trace Event', N'Occurs when a statement checks for the ALTER TRACE permission.'
                                            , N'Возникает при проверке инструкцией наличия разрешения ALTER TRACE.'
union all 
select 176, 'Audit Server Object Management Event', N'Occurs when server objects are created, altered, or dropped.'
                                                  , N'Возникает при создании, изменении и удалении серверных объектов.'
union all 
select 177, 'Audit Server Principal Management Event', N'Occurs when server principals are created, altered, or dropped.'
                                                     , N'Возникает при создании, изменении и удалении участников [системы безопасности] на уровне сервера.'
union all 
select 178, 'Audit Database Operation Event', N'Occurs when database operations occur, such as checkpoint or subscribe query notification.'
                                            , N'Возникает при таких операциях базы данных, как уведомление запроса контрольной точки или подписки.'
union all 
select 180, 'Audit Database Object Access Event', N'Occurs when database objects, such as schemas, are accessed.'
                                                , N'Возникает при доступе к таким объектам базы данных, как схема.'
union all 
select 181, 'TM: Begin Tran starting', N'Occurs when a BEGIN TRANSACTION request starts.'
                                     , N'Возникает при запуске запроса BEGIN TRANSACTION.'
union all 
select 182, 'TM: Begin Tran completed', N'Occurs when a BEGIN TRANSACTION request completes.'
                                      , N'Возникает при завершении запроса BEGIN TRANSACTION.'
union all 
select 183, 'TM: Promote Tran starting', N'Occurs when a PROMOTE TRANSACTION request starts.'
                                       , N'Возникает при запуске запроса PROMOTE TRANSACTION.'
union all 
select 184, 'TM: Promote Tran completed', N'Occurs when a PROMOTE TRANSACTION request completes.'
                                        , N'Возникает при завершении запроса PROMOTE TRANSACTION.'
union all 
select 185, 'TM: Commit Tran starting', N'Occurs when a COMMIT TRANSACTION request starts.'
                                      , N'Возникает при запуске запроса COMMIT TRANSACTION.'
union all 
select 186, 'TM: Commit Tran completed', N'Occurs when a COMMIT TRANSACTION request completes.'
                                       , N'Возникает при завершении запроса COMMIT TRANSACTION.'
union all 
select 187, 'TM: Rollback Tran starting', N'Occurs when a ROLLBACK TRANSACTION request starts.'
                                        , N'Возникает при запуске запроса ROLLBACK TRANSACTION.'
union all 
select 188, 'TM: Rollback Tran completed', N'Occurs when a ROLLBACK TRANSACTION request completes.'
                                         , N'Возникает при завершении запроса ROLLBACK TRANSACTION.'
union all 
select 189, 'Lock:Timeout (timeout > 0)', N'Occurs when a request for a lock on a resource, such as a page, times out.'
                                        , N'Возникает при истечении времени ожидания запроса на блокировку ресурса, например страницы.'
union all 
select 190, 'Progress Report: Online Index Operation', N'Reports the progress of an online index build operation while the build process is running.'
                                                     , N'Сообщает о ходе выполнения операции оперативного построения индекса при работающем процессе построения.'
union all 
select 191, 'TM: Save Tran starting', N'Occurs when a SAVE TRANSACTION request starts.'
                                    , N'Возникает при запуске запроса SAVE TRANSACTION.'
union all 
select 192, 'TM: Save Tran completed', N'Occurs when a SAVE TRANSACTION request completes.'
                                     , N'Возникает при завершении запроса SAVE TRANSACTION.'
union all 
select 193, 'Background Job Error', N'Occurs when a background job terminates abnormally.'
                                  , N'Возникает при аварийном завершении фонового задания.'
union all 
select 194, 'OLEDB Provider Information', N'Occurs when a distributed query runs and collects information corresponding to the provider connection.'
                                        , N'Возникает, если запускается распределенный запрос, который собирает сведения, относящиеся к соединению поставщика.'
union all 
select 195, 'Mount Tape', N'Occurs when a tape mount request is received.'
                        , N'Возникает при получении запроса на монтирование ленты.'
union all 
select 196, 'Assembly Load', N'Occurs when a request to load a CLR assembly occurs.'
                           , N'Возникает при запросе на загрузку сборки среды CLR.'
union all 
select 197, 'Reserved', N'', N''
union all 
select 198, 'XQuery Static Type', N'Occurs when an XQuery expression is executed. This event class provides the static type of the XQuery expression.'
                                , N'Возникает при выполнении выражения языка XQuery. Этот класс событий представляет статический тип выражения XQuery.'
union all 
select 199, 'QN: subscription', N'Occurs when a query registration cannot be subscribed. The TextData column contains information about the event.'
                              , N'Возникает, когда регистрация запроса не может быть подписана. Столбец TextData содержит сведения о событии.'
union all 
select 200, 'QN: parameter table', N'Information about active subscriptions is stored in internal parameter tables. This event class occurs when a parameter table is created or deleted. Typically, these tables are created or deleted when the database is restarted. The TextData column contains information about the event.'
                                 , N'Сведения об активных подписках хранятся во внутренней таблице параметров. Этот класс событий возникает, если создается или удаляется таблица параметров. Обычно такие таблицы создаются или удаляются при перезапуске базы данных. Столбец TextData содержит сведения о событии.'
union all 
select 201, 'QN: template', N'A query template represents a class of subscription queries. Typically, queries in the same class are identical except for their parameter values. This event class occurs when a new subscription request falls into an already existing class of (Match), a new class (Create), or a Drop class, which indicates cleanup of templates for query classes without active subscriptions. The TextData column contains information about the event.'
                          , N'Шаблон запроса представляет класс запросов на подписку. Как правило, запросы того же класса идентичны за исключением значений их параметров. Это событие возникает, если новый запрос на подписку принадлежит существующему классу (Match), новому классу (Create) или классу Drop, который указывает на очистку шаблонов классов запросов, не имеющих активных подписок. Столбец TextData содержит сведения о событии.'
union all 
select 202, 'QN: dynamics', N'Tracks internal activities of query notifications. The TextData column contains information about the event.'
                          , N'Отслеживает внутреннюю деятельность уведомлений запросов. Столбец TextData содержит сведения о событии.'


2) А теперь таблицу колонок:

--Заполняем таблицу колонок
insert into dbo.Trace_Columns
select 1, 'TextData', N'Text value dependent on the event class that is captured in the trace.'
                    , N'Текстовое значение, зависящее от класса событий, фиксируемых при трассировке.'
union all 
select 2, 'BinaryData', N'Binary value dependent on the event class captured in the trace.'
                      , N'Значение типа Binary, зависящее от класса событий, фиксируемых при трассировке.'
union all 
select 3, 'DatabaseID', N'ID of the database specified by the USE database statement, or the default database if no USE database statement is issued for a given connection.The value for a database can be determined by using the DB_ID function.'
                      , N'Идентификатор базы данных, указанный в инструкции USE database, или база данных по умолчанию, если для данного соединения инструкция USE database не выполнялась.Значение для базы данных можно определить с помощью функции DB_ID.'
union all 
select 4, 'TransactionID', N'System-assigned ID of the transaction.'
                         , N'Назначенный системой идентификатор транзакции.'
union all 
select 5, 'LineNumber', N'Contains the number of the line that contains the error. For events that involve Transact-SQL statements, like SP:StmtStarting, the LineNumber contains the line number of the statement in the stored procedure or batch.'
                      , N'Содержит номер строки, в которой имеется ошибка. Для событий, в которых задействованы инструкции языка Transact-SQL, например SP:StmtStarting, столбец LineNumber содержит номер строки инструкции в хранимой процедуре или пакете.'
union all 
select 6, 'NTUserName', N'Microsoft Windows user name.'
                      , N'Имя пользователя Microsoft Windows.'
union all 
select 7, 'NTDomainName', N'Windows domain to which the user belongs.'
                        , N'Домен Windows, к которому принадлежит пользователь.'
union all 
select 8, 'HostName', N'Name of the client computer that originated the request.'
                    , N'Имя клиентского компьютера, отправившего запрос.'
union all 
select 9, 'ClientProcessID', N'ID assigned by the client computer to the process in which the client application is running.'
                           , N'Идентификатор, присвоенный клиентским компьютером процессу, в котором работает клиентское приложение.'
union all 
select 10, 'ApplicationName', N'Name of the client application that created the connection to an instance of SQL Server. This column is populated with the values passed by the application rather than the displayed name of the program.'
                            , N'Имя клиентского приложения, установившего соединение с экземпляром SQL Server. Этот столбец заполняется значениями, передаваемыми приложением, а не отображаемым именем программы.'
union all 
select 11, 'LoginName', N'SQL Server login name of the client.'
                      , N'Имя входа SQL Server для клиента.'
union all 
select 12, 'SPID', N'Server Process ID assigned by SQL Server to the process associated with the client.'
                 , N'Идентификатор процесса сервера, который SQL Server присвоил процессу, связанному с клиентом.'
union all 
select 13, 'Duration', N'Amount of elapsed time (in microseconds) taken by the event. This data column is not populated by the Hash Warning event.'
                     , N'Длительность события (в микросекундах). Этот столбец данных не заполняется событием Hash Warning.'
union all 
select 14, 'StartTime', N'Time at which the event started, when available.'
                      , N'Время начала события, если оно доступно.'
union all 
select 15, 'EndTime', N'Time at which the event ended. This column is not populated for starting event classes, such as SQL:BatchStarting or SP:Starting. It is also not populated by the Hash Warning event.'
                    , N'Время окончания события. Этот столбец не заполняется для классов событий запуска, таких как SQL:BatchStarting или SP:Starting. Он также не заполняется событием Hash Warning.'
union all 
select 16, 'Reads', N'Number of logical disk reads performed by the server on behalf of the event. This column is not populated by the Lock:Released event.'
                  , N'Число логических чтений диска, выполненное сервером для данного события. Этот столбец не заполняется событием Lock:Released.'
union all 
select 17, 'Writes', N'Number of physical disk writes performed by the server on behalf of the event.'
                   , N'Число логических обращений к дискам на запись, выполненное сервером для данного события.'
union all 
select 18, 'CPU', N'Amount of CPU time (in milliseconds) used by the event.'
                , N'Объем времени ЦП (в миллисекундах), использованного событием.'
union all 
select 19, 'Permissions', N'"Represents the bitmap of permissions; used by Security Auditing."'
                        , N'Представляет битовую карту разрешений. Используется событием Security Auditing.'
union all 
select 20, 'Severity', N'Severity level of an exception.'
                     , N'Уровень серьезности исключения.'
union all 
select 21, 'EventSubClass', N'Type of event subclass. This data column is not populated for all event classes.'
                          , N'Тип подкласса событий. Этот столбец данных не заполняется для всех классов событий.'
union all 
select 22, 'ObjectID', N'System-assigned ID of the object.', N'Назначенный системой идентификатор объекта.'
union all 
select 23, 'Success', N'"Success of the permissions usage attempt; used for auditing: 1 = success; 0 = failure'
                    , N'Успех попытки использования разрешений. Применяется для аудита: 1 (успешное завершение) или 0 (неуспешное завершение)'
union all 
select 24, 'IndexID', N'ID for the index on the object affected by the event. To determine the index ID for an object, use the indid column of the sysindexes system table.'
                    , N'Идентификатор индекса объекта, связанного с событием. Чтобы определить идентификатор индекса для объекта, используйте столбец indid в системной таблице sysindexes.'
union all 
select 25, 'IntegerData', N'Integer value dependent on the event class captured in the trace.'
                        , N'Целочисленное значение, зависящее от класса событий, собираемых при трассировке.'
union all 
select 26, 'ServerName', N'Name of the instance of SQL Server, either servername or servername\instancename, being traced.'
                       , N'Имя экземпляра SQL Server (servername или servername\instancename), который отслеживается в настоящий момент.'
union all 
select 27, 'EventClass', N'Type of event class being recorded.'
                       , N'Тип класса событий, который записывается в настоящий момент.'
union all 
select 28, 'ObjectType', N'Type of object, such as: table, function, or stored procedure.'
                       , N'Тип объекта, например: таблица, функция или хранимая процедура.'
union all 
select 29, 'NestLevel', N'The nesting level at which this stored procedure is executing. See @@NESTLEVEL (Transact-SQL).'
                      , N'Уровень вложенности, на котором выполняется хранимая процедура. Дополнительные сведения см. в разделе @@NESTLEVEL (Transact-SQL).'
union all 
select 30, 'State', N'Server state, in case of an error.'
                  , N'Состояние сервера в случае ошибки.'
union all 
select 31, 'Error', N'Error number.'
                  , N'Номер ошибки.'
union all 
select 32, 'Mode', N'Lock mode of the lock acquired. This column is not populated by the Lock:Released event.'
                 , N'Режим полученной блокировки. Этот столбец не заполняется событием Lock:Released.'
union all 
select 33, 'Handle', N'Handle of the object referenced in the event.'
                   , N'Дескриптор объекта, на который ссылается событие.'
union all 
select 34, 'ObjectName', N'Name of object accessed.'
                       , N'Имя объекта, к которому выполняется доступ.'
union all 
select 35, 'DatabaseName', N'Name of the database specified in the USE database statement.'
                         , N'Имя базы данных, указанное в инструкции USE database.'
union all 
select 36, 'FileName', N'Logical name of the file name modified.'
                     , N'Логическое имя изменяемого файла.'
union all 
select 37, 'OwnerName', N'Owner name of the referenced object.'
                      , N'Имя владельца для объекта ссылки.'
union all 
select 38, 'RoleName', N'Name of the database or server-wide role targeted by a statement.'
                     , N'Имя базы данных или серверной роли, к которым получает доступ инструкция.'
union all 
select 39, 'TargetUserName', N'User name of the target of some action.'
                           , N'Пользовательское имя цели некоторой операции.'
union all 
select 40, 'DBUserName', N'SQL Server database user name of the client.'
                       , N'Имя пользовательской базы данных SQL Server для клиента.'
union all 
select 41, 'LoginSid', N'Security identifier (SID) of the logged-in user.'
                     , N'Идентификатор безопасности (SID) вошедшего в систему пользователя.'
union all 
select 42, 'TargetLoginName', N'Login name of the target of some action.'
                            , N'Имя входа цели некоторой операции.'
union all 
select 43, 'TargetLoginSid', N'SID of the login that is the target of some action.'
                           , N'Идентификатор безопасности имени входа, которое является целью некоторой операции.'
union all 
select 44, 'ColumnPermissions', N'"Column-level permissions status; used by Security Auditing."'
                              , N'Состояние разрешений на уровне столбцов. Используется событием Security Auditing.'
union all 
select 45, 'LinkedServerName', N'Name of the linked server.'
                             , N'Имя связанного сервера.'
union all 
select 46, 'ProviderName', N'Name of the OLE DB provider.'
                         , N'Имя поставщика OLE DB.'
union all 
select 47, 'MethodName', N'Name of the OLE DB method.'
                       , N'Имя метода OLE DB.'
union all 
select 48, 'RowCounts', N'Number of rows in the batch.'
                      , N'Количество строк в пакете.'
union all 
select 49, 'RequestID', N'ID of the request containing the statement.'
                      , N'Идентификатор запроса, содержащего инструкцию.'
union all 
select 50, 'XactSequence', N'A token to describe the current transaction.'
                         , N'Маркер для описания текущей транзакции.'
union all 
select 51, 'EventSequence', N'Sequence number for this event.'
                          , N'Порядковый номер этого события.'
union all 
select 52, 'BigintData1', N'bigint value, which is dependent on the event class captured in the trace.'
                        , N'Значение типа bigint, зависящее от класса событий, захваченного при трассировке.'
union all 
select 53, 'BigintData2', N'bigint value, which is dependent on the event class captured in the trace.'
                        , N'Значение типа bigint, зависящее от класса событий, захваченного при трассировке.'
union all 
select 54, 'GUID', N'GUID value, which is dependent on the event class captured in the trace.'
                 , N'Значение идентификатора GUID, зависящее от класса события, захваченного при трассировке.'
union all 
select 55, 'IntegerData2', N'Integer value, which is dependent on the event class captured in the trace.'
                         , N'Целое число, значение которого зависит от класса событий, захваченного при трассировке.'
union all 
select 56, 'ObjectID2', N'ID of the related object or entity, if available.'
                      , N'Идентификатор связанного объекта или сущности, если он доступен.'
union all 
select 57, 'Type', N'Integer value, which is dependent on the event class captured in the trace.'
                 , N'Целое число, значение которого зависит от класса событий, захваченного при трассировке.'
union all 
select 58, 'OwnerID', N'Type of the object that owns the lock. For lock events only.'
                    , N'Тип объекта-владельца блокировки. Только для событий блокировки.'
union all 
select 59, 'ParentName', N'Name of the schema the object is within.'
                       , N'Имя схемы, в которой находится объект.'
union all 
select 60, 'IsSystem', N'Indicates whether the event occurred on a system process or a user process: 1 = system; 0 = user.'
                     , N'Указывает, произошло ли событие в системном или в пользовательском процессе: 1 = системный процесс; 0 = пользовательский процесс.'
union all 
select 61, 'Offset', N'Starting offset of the statement within the stored procedure or batch.'
                   , N'Начальное смещение инструкции в пределах хранимой процедуры или пакета.'
union all 
select 62, 'SourceDatabaseID', N'ID of the database in which the source of the object exists.'
                             , N'Идентификатор базы данных, в которой находится источник объекта.'
union all 
select 63, 'SqlHandle', N'64-bit hash based on the text of an ad hoc query or the database and object ID of an SQL object. This value can be passed to sys.dm_exec_sql_text() to retrieve the associated SQL text.'
                      , N'64-разрядный хэш, основанный на тексте нерегламентированного запроса или базы данных и идентификаторе объекта SQL. Это значение может быть передано в функцию sys.dm_exec_sql_text(), чтобы получить связанный SQL-текст.'
union all 
select 64, 'SessionLoginName', N'The login name of the user who originated the session. For example, if you connect to SQL Server using Login1 and execute a statement as Login2, SessionLoginName displays Login1, while LoginName displays Login2. This data column displays both SQL Server and Windows logins.'
                             , N'Имя входа пользователя, который инициировал сеанс. Например, при подключении к SQL Server под именем Имя_входа1 и при выполнении инструкции под именем Имя_входа2 поле SessionLoginName будет содержать Имя_входа1, а поле LoginName — Имя_входа2. В данном столбце отображаются имена входа SQL Server и Windows.'


Эти таблицы не более, чем справочник событий и колонок, они нам потребуются для создания шаблона трассировки и, возможно, для последующего анализа запуска нашей процедуры трассировки.

А теперь текст самой процедуры, а потом я немного объясню как с ней работать, и какие у неё входные параметры:

use master
go
if ( object_id( N'dbo.Trace', 'P' ) is not null )
  drop procedure dbo.Trace
go

/*
--  Процедура трассирования событий на сервере
  
--  Результат работы: 0 - Успешно отработала
--                    1 - Ошибка входных пар-ов
--                    2 - Ошибка создания трассы
--                    3 - Ошибка создания события/событий
--                    4 - Ошибка создания фильтра/фильтров
--                    5 - Ошибка запуска/остановки/закрытия трассы
--                    6 - Ошибка входных пар-ов

--  Список всех событий: таблица dbo.Trace_Events
--  Список всех колонок: таблица dbo.Trace_Columns
  
--  Формат входной таблицы событий для конкретной трассы ( @event ) :
--          create table [Имя таблицы] ( event_id  int  --Идентификатор события ( из dbo.Trace_Events )
--                                     , column_id int  --Идентификатор колонки ( из dbo.Trace_Columns )
--                                     , [on]      bit  --Вкл/Выкл
--                                     )
                               
--  Формат входной фильтр-таблицы для конкретной трассы ( @filter ):
--          create table [Имя таблицы] ( column_id           int              --Идентификатор колонки ( из dbo.Trace_Columns )
--                                     , logical_operator    int              --0:AND; 1:OR
--                                     , comparison_operator int              --0:'='; 1:'<>'; 2:'>'; 3:'<'; 4:'>='; 
--                                                                            --5:'<='; 6:'LIKE'; 7:'NOT LIKE' 
--                                     , value               nvarchar(1024)   --Значение фильтра
--                                     )


--Пример запуска:  
---------------
--  declare @tracefile nvarchar(255)
--        , @ret int
--  set @tracefile = N'C:\trace\trace_'+convert( varchar(10), getdate(), 105 )
                 
--  exec @ret = dbo.Trace @tracefile = @tracefile
--                      , @options = 6
--                      , @max_file_size = 10
--                      , @stop_time = '20101231 22:00'
--                      , @event = N'master.dbo.events'
--                      , @filter = N'master.dbo.filters'
                      
--  select @ret    
---------------
    
*/
    
create procedure dbo.Trace 
    @tracefile nvarchar(255)  --Имя трассировочного файла
  , @options int              --Настройки 2:TRACE_FILE_ROLLOVER; 4:SHUTDOWN_ON_ERROR; 8:TRACE_PRODUCE_BLACKBOX   
  , @max_file_size bigint     --Размер трассировочного файла (Мб)
  , @stop_time datetime       --Время остановки трассы
  , @event nvarchar(128)      --Имя с таблицей событий + колонок
  , @filter nvarchar(128)     --Имя таблицы с фильтрами
as
begin
set nocount on

    declare @ret int
          , @ret_message nvarchar(2048)
          , @trace_id  int            
          , @event_id int
          , @column_id int
          , @on bit
          , @logical_operator int
          , @comparison_operator int 
          , @value nvarchar (1024)

    if (  @options not in ( 2, 4, 6, 8 ) )
    begin
    select 'Ошибка: Настройки могут иметь значения 2, 4, 6 ( 2 + 4 ) или 8'
    return 1
    end 

    if (  @max_file_size < 5 )
    begin
    select 'Ошибка: Размер трассировочного файла не может быть < 5Mb'
    return 1
    end 

    if (  @stop_time < getdate() )
    begin
    select 'Ошибка: Время остановки трассы должно быть больше, чем текущее на сервере'
    return 1
    end 

    if ( object_id( @event, 'U' ) is null )
    begin
    select 'Ошибка: Таблица событий не существует, уточните контекст БД и схему объекта'
    return 1
    end 

    if ( object_id( @filter, 'U' ) is null )
    begin
    select 'Ошибка: Таблица с фильтрами не существует, уточните контекст БД и схему объекта'
    return 1
    end 
          
    set @ret_message = 'Создание новой трассы!'
    insert into dbo.Trace_logs ( trace_id, ret_message )
      values ( @trace_id, @ret_message )
         
    exec @ret = sp_trace_create @traceid     = @trace_id out
                              , @options     = @options 
                              , @tracefile   = @tracefile 
                              , @maxfilesize = @max_file_size 
                              , @stoptime    = dateadd( mi, 10, @stop_time )
    
    select @ret = @@error where @@error != 0 
    if ( @ret != 0 ) goto error_sp_trace_create

    set @ret_message = 'Трасса успешно создана!'
    insert into dbo.Trace_logs ( trace_id, stop_time, tracefile, file_size, ret_message )
      values ( @trace_id, @stop_time, @tracefile, @max_file_size, @ret_message )

    --Генерим события
    create table #Events ( event_id int
                         , column_id int
                         , [on] bit 
                         )
    exec ( 'insert into #Events select * from ' + @event )
    
    declare curEvents cursor for select * from #Events order by event_id, column_id 
    open curEvents 
    while ( 1 = 1 )
    begin
      fetch next from curEvents into @event_id, @column_id, @on
        exec @ret = sp_trace_setevent @traceid = @trace_id
                                    , @eventid = @event_id
                                    , @columnid = @column_id
                                    , @on = @on
        select @ret = @@error where @@error != 0 
        if ( @ret != 0 ) goto error_sp_trace_setevent
        
      if ( @@fetch_status != 0 ) break
      
        set @ret_message = 'Создано событие ' + cast( @event_id as varchar(3) ) 
                               + '; колонка ' + cast( @column_id as varchar(3) )
                               + '; on = ' + cast( @on as char(1) )
        insert into dbo.Trace_logs ( trace_id, ret_message )
          values ( @trace_id, @ret_message )
    end
    close curEvents
    deallocate curEvents 


    --Задаем фильтр
    create table #Filters ( column_id int
                          , logical_operator int
                          , comparison_operator int
                          , value nvarchar(1024)
                          )
    exec ( 'insert into #Filters select * from ' + @filter )
    
    declare curFilters cursor for select * from #Filters order by column_id 
    open curFilters 
    while ( 1 = 1 )
    begin
      fetch next from curFilters into @column_id, @logical_operator, @comparison_operator, @value 
        exec @ret = sp_trace_setfilter @traceid = @trace_id
                                     , @columnid = @column_id
                                     , @logical_operator = @logical_operator
                                     , @comparison_operator = @comparison_operator
                                     , @value = @value
        select @ret = @@error where @@error != 0 
        if ( @ret != 0 ) goto error_sp_trace_setfilter
        
      if ( @@fetch_status != 0 ) break
      
        set @ret_message = 'Создан фильтр на колонку ' + cast( @column_id as varchar(3) )
                               + '; @logical_operator = ' + case @logical_operator 
                                                              when 0 then 'AND (0)' 
                                                              when 1 then 'OR (1)' 
                                                            end
                               + '; ' + case @comparison_operator 
                                          when 0 then '= (равно)' 
                                          when 1 then '<> (не равно)'
                                          when 2 then '> (больше)'
                                          when 3 then '< (меньше)' 
                                          when 4 then '>= (больше или равно)' 
                                          when 5 then '<= (меньше или равно)'
                                          when 6 then 'LIKE' 
                                          when 7 then 'NOT LIKE'                                                                                      
                                        end
                               + ' "' + @value + '"'
        insert into dbo.Trace_logs ( trace_id, ret_message )
          values ( @trace_id, @ret_message )
    end
    close curFilters
    deallocate curFilters 
    

    --Запускаем трассировку
    exec @ret = sp_trace_setstatus @traceid = @trace_id
                                 , @status  = 1 -- 0:остановка; 1:запуск; 2:закрыть 

    select @ret = @@error where @@error != 0 
    if ( @ret != 0 ) goto error_sp_trace_setstatus

    set @ret_message = 'Трасса запущена!'
    insert into dbo.Trace_logs ( trace_id, start_time, stop_time, tracefile, file_size, ret_message )
      values ( @trace_id, getdate(), @stop_time, @tracefile, @max_file_size, @ret_message )
      
    
    while ( 1 = 1 )
    begin
      waitfor delay '00:05' -- раз в 5 минут проверяем не пора ли остановить трассировку :)))
      if ( @stop_time <= getdate() )
      begin
        --Останавливаем трассировку
        exec @ret = sp_trace_setstatus @traceid = @trace_id
                                     , @status  = 0 -- 0:остановка; 1:запуск; 2:закрыть 

        select @ret = @@error where @@error != 0 
        if ( @ret != 0 ) goto error_sp_trace_setstatus

        set @ret_message = 'Трасса остановлена!'
        insert into dbo.Trace_logs ( trace_id, stop_time, tracefile, file_size, ret_message )
          values ( @trace_id, @stop_time, @tracefile, @max_file_size, @ret_message )
          
        --Закрываем трассировку
        exec @ret = sp_trace_setstatus @traceid = @trace_id
                                     , @status  = 2 -- 0:остановка; 1:запуск; 2:закрыть 

        select @ret = @@error where @@error != 0 
        if ( @ret != 0 ) goto error_sp_trace_setstatus

        set @ret_message = 'Трасса закрыта!'
        insert into dbo.Trace_logs ( trace_id, stop_time, tracefile, file_size, ret_message )
          values ( @trace_id, @stop_time, @tracefile, @max_file_size, @ret_message )
          
        break    
      end
    end

    
    return 0 --Успешно отработала процедура   
    
--Ошибка создания трассы
error_sp_trace_create:
    set @ret_message = 'Ошибка создания трассы - '
                      + case @ret
                          when 1  then 'Неизвестная ошибка.'
                          when 10 then 'Недопустимые параметры. Возвращается, если указанные параметры несовместимы.'
                          when 12 then 'Файл не создан.'
                          when 13 then 'Нехватка памяти. Возвращается, если для выполнения указанного действия недостаточно памяти.'
                          when 14 then 'Недопустимое время останова. Возвращается, если указанное время останова уже прошло.'
                          when 15 then 'Недопустимые аргументы. Возвращается, если пользователь ввел несовместимые аргументы.'           
                          else '№ ошибки: ' + cast( @ret as varchar(5) )
                        end 
    insert into dbo.Trace_logs ( trace_id, error, ret_message )
      values ( @trace_id, 2, @ret_message )
    return 2
       
--Ошибка создания события
error_sp_trace_setevent:      
    set @ret_message = 'Ошибка создания события - '
                      + case @ret
                          when 1  then 'Неизвестная ошибка.'
                          when 2  then 'Трассировка в данный момент выполняется. Изменение трассировки в это время приведет к ошибке.'
                          when 3  then 'Указанное событие недопустимо. Возможно, событие не существует или не соответствует ни одной хранимой процедуре.'
                          when 4  then 'Указан недопустимый столбец.'
                          when 9  then 'Указан недопустимый дескриптор трассировки.'
                          when 11 then 'Указанный столбец используется для внутренних целей и не может быть удален.'
                          when 13 then 'Недостаточно памяти. Возвращается, если для выполнения указанного действия недостаточно памяти.'
                          when 16 then 'Недопустимая функция для данной трассировки.'                          
                          else '№ ошибки: ' + cast( @ret as varchar(5) )
                        end
    insert into dbo.Trace_logs ( trace_id, error, ret_message )
      values ( @trace_id, 3, @ret_message ) 
    return 3   

--Ошибка создания фильтра
error_sp_trace_setfilter:      
    set @ret_message = 'Ошибка создания фильтра - '
                      + case @ret
                          when 1  then 'Неизвестная ошибка.'
                          when 2  then 'Трассировка в данный момент выполняется. Изменение трассировки в это время приведет к ошибке.'
                          when 4  then 'Указан недопустимый столбец.'
                          when 5  then 'Нельзя выполнить фильтрацию по указанному столбцу. Это значение возвращается только процедурой sp_trace_setfilter.'
                          when 6  then 'Указан недопустимый оператор сравнения.'
                          when 7  then 'Указан недопустимый логический оператор.'
                          when 9  then 'Указан недопустимый дескриптор трассировки.'
                          when 13 then 'Недостаточно памяти. Возвращается, если для выполнения указанного действия недостаточно памяти.'
                          when 16 then 'Недопустимая функция для данной трассировки.'                          
                          else '№ ошибки: ' + cast( @ret as varchar(5) )
                        end
    insert into dbo.Trace_logs ( trace_id, error, ret_message )
      values ( @trace_id, 4, @ret_message ) 
    return 4      
                  
--Ошибка запуска/остановки/закрытия трассы
error_sp_trace_setstatus:
    set @ret_message = 'Ошибка запуска/остановки/закрытия трассы - '
                      + case @ret
                          when 1  then 'Неизвестная ошибка.'
                          when 8  then 'Указано недопустимое состояние.'
                          when 9  then 'Указан недопустимый дескриптор трассировки.'
                          when 13 then 'Не хватает памяти. Возвращается, когда для выполнения указанного действия недостаточно памяти.'
                          else '№ ошибки: ' + cast( @ret as varchar(5) )
                        end
    insert into dbo.Trace_logs ( trace_id, error, ret_message )
      values ( @trace_id, 5, @ret_message )
    return 5
end



Пример запуска процедуры очень прост:

declare @tracefile nvarchar(255)
      , @ret int
set @tracefile = N'C:\trace\trace_'+convert( varchar(10), getdate(), 105 )
                 
exec @ret = dbo.Trace @tracefile = @tracefile
                    , @options = 6
                    , @max_file_size = 10
                    , @stop_time = '20101231 22:00'
                    , @event = N'master.dbo.events'
                    , @filter = N'master.dbo.filters'
                      
select @ret


Про входные пар-ры чуть-чуть подробнее:

@tracefile - Путь и имя файла трассировки на сервере или UNC-путь к файлу (у УЗ дожен быть доступ к указанному пути для сохранения результата в файл; расширение файлу можно не указывать, т.к. оно создастся автоматически)

@options - Указывает набор параметров для трассировки. Аргумент option_value имеет тип int и не имеет значения по умолчанию. Пользователи могут выбирать сочетания этих параметров путем указания их суммарного значения. Например, чтобы установить параметры TRACE_FILE_ROLLOVER и SHUTDOWN_ON_ERROR, достаточно задать значение 6 для аргумента option_value.

В следующей таблице содержится список параметров, их значений и описаний.

Имя параметра Значение параметра Описание

TRACE_FILE_ROLLOVER

2

Указывает, что при достижении размера аргумента max_file_size текущий трассировочный файл закрывается и создается новый. Все новые записи будут сохраняться в новый файл. Новый файл будет иметь то же имя, что и предыдущий, но в конец имени будет добавлено число, показывающее его порядковый номер. Например, если изначально трассировочный файл назывался filename.trc, то следующий трассировочный файл будет называться filename_1.trc, имя следующего трассировочного файла будет filename_2.trc и т. д.

По мере увеличения количества трассировочных файлов число, добавляемое в конец имени файла, будет также последовательно увеличиваться.

SQL Server по умолчанию в качестве значения аргумента max_file_size использует 5 МБ, если он указан без указания значения аргумента max_file_size.

SHUTDOWN_ON_ERROR

4

Указывает, что если трассировка не может быть записана в файл по какой-либо причине, SQL Server останавливается. Этот параметр полезен в случае проведения трассировок по проверке безопасности.

TRACE_PRODUCE_BLACKBOX

8

Указывает, что запись последних 5 МБ трассировочных сведений, формируемых сервером, будет сохранена на сервере. Значение параметра TRACE_PRODUCE_BLACKBOX несовместимо со всеми другими.

@max_file_size - Указывает максимальный размер трассировочного файла в мегабайтах (МБ). Аргумент max_file_size имеет тип bigint и значение по умолчанию 5. Если этот аргумент указан без параметра TRACE_FILE_ROLLOVER, трассировка остановит запись в файл, когда используемое дисковое пространство достигнет значения, установленного в аргументе max_file_size.


@stop_time - Указывает дату и время, когда трассировка будет остановлена. Остановка делается внутри процедуры, раз в 5 минут процедура проверяет не наступило ли указанное время, чтобы подстраховаться таймер автоматом устанавливает время для остановки трассы на 10 минут больше чем входной параметр. Даже если по какой-то причине процедура не остановит трассу, это произайдёт автоматически, без занесения информации в лог, но тем самым мы подстрахованы от "бесконечной" работы трассы до окончания свободного места на сервере.

@event - таблица-шаблон трассы, формат таблицы:

--  Формат входной таблицы событий для конкретной трассы ( @event ) :
--          create table [Имя таблицы] ( event_id  int  --Идентификатор события ( из dbo.Trace_Events )
--                                     , column_id int  --Идентификатор колонки ( из dbo.Trace_Columns )
--                                     , [on]      bit  --Вкл/Выкл
--                                     )

Отмечу, что для каждого события необходимо указать отдельно все колонки для сбора информации, т.е. для одного значения-события могут быть от 1 до 64 колонок. В таблице-справочние 202 события, но для SQL Server 2000 доступны только первые 118, а колонок только первые 44 из 64. Остальные события и колонки доступны в версиях 2005 и выше.

@filter - таблица-фильтр трассы, формат таблицы:

--  Формат входной фильтр-таблицы для конкретной трассы ( @filter ):
--          create table [Имя таблицы] ( column_id           int              --Идентификатор колонки ( из dbo.Trace_Columns )
--                                     , logical_operator    int              --0:AND; 1:OR
--                                     , comparison_operator int              --0:'='; 1:'<>'; 2:'>'; 3:'<'; 4:'>='; 
--                                                                            --5:'<='; 6:'LIKE'; 7:'NOT LIKE' 
--                                     , value               nvarchar(1024)   --Значение фильтра
--                                     )



Для трассировки сервера БД достаточно создать несколько шаблонов трассировки и несколько таблиц-фильтров, а саму процедуру "повесить" на расписание, в качестве входных пар-ров можно варьировать шаблоны и фильтры.
Для дальнейшего анализа собранной информации в виде таблицы можно использовать функцию fn_trace_gettable.




P.S.
В моей процедуре используются основные процедуры трассировки:
sp_trace_create - Создает определение трассировки. Новая трассировка будет находиться в остановленном состоянии.
sp_trace_setevent - Добавляет к трассировке или удаляет из нее событие либо столбец событий. Хранимую процедуру sp_trace_setevent можно выполнять только в остановленных существующих трассировках (параметр status равен 0). Будет возвращена ошибка, если эта хранимая процедура выполняется в несуществующей трассировке или параметр status которой не равен 0.
sp_trace_setfilter - Применяет фильтр к трассировке. Хранимая процедура sp_trace_setfilter может выполняться только для существующих остановленных трассировок (свойство status равно 0). SQL Server возвращает ошибку, если эта хранимая процедура выполняется для трассировки, которой не существует или значение свойства status которой не равно 0.
sp_trace_setstatus - Изменяет текущее состояние указанной трассировки.

Tags: , , ,

SQL Server

SQL Server Management Studio зависает

by Alexey Knyazev 11. мая 2010 22:47

Периодически на форумах возникает вопрос, подобный этим:

  • "Почему SQL Server Management Studio так медленно работает?"
  • "SSMS постоянно виснет"
  • "Почему Management Studio так долго открывается/закрывается".

Для решения подобных проблем, предлагаю проделать кое какие действия:


1. Убедитесь, что ваша рабочая станция соответствует всем минимальным требованиям, как в плане "железа", так и софта, для работы SSMS (SQL Server Management Studio)
Например для удовлетворительно работы Microsoft® SQL Server® 2008 Management Studio Express потребуется:


Системные требования

  • Поддерживаемые операционные системы: Windows 7; Windows Server 2003 Service Pack 2; Windows Server 2008; Windows Server 2008 R2; Windows Vista; Windows Vista Service Pack 1; Windows XP Service Pack 2; Windows XP Service Pack 3
  • 32-разрядные системы: компьютер, оборудованный процессором Intel или совместимым процессором с тактовой частотой 1 ГГц или выше (рекомендуется 2 ГГц или выше, поддерживается только один процессор)
  • 64-разрядные системы: процессор с тактовой частотой 1,4 ГГц или выше (рекомендуется 2 ГГц или выше, поддерживается только один процессор)
  • Минимальный объем ОЗУ 512 МБ (рекомендуется 1 ГБ или более)
  • 1 ГБ свободного места на диске


2. Посмотрите версию вашего клиента ( "Help" -> "About" ), возможно стоит обновиться до последнего SP (сервис пака) или существует SQL Server Hotfix, который может решить ваши проблемы. Список доступных версий можно посмотреть по ссылке http://www.t-sql.ru/page/versions.aspx.


3. Возможно какое-то из Ваших приложений «мешает» работе SSMS, например антивирус, убедитесь, что он верно настроен.

 
4. Опять же не поленитесь обновить ваши антивирусные базы и просканируйте компьютер на наличие вредоносного кода (вирусы, черви и т.д.).

5. Запретите загрузку помощи из сети: "Tools" -> "Options" -> "Help" -> "Online" укажите "Try local first, not online".


6. Отключите проверку аннулированных сертификатов в "Internet Explorer" -> "Tools" -> "Internet Options" -> "Advanced" и снять «галки» с Check for server certificate revocation и Check for publisher's certificate revocation
(Подробнее: http://msmvps.com/blogs/gladchenko/archive/2007/01/16/497463.aspx)


7. Отключите отображение экрана-заставки при открытии среды SQL Server Management Studio. Правой кнопкой мыши по ярлыку SSMS и в свойствах добавьте параметр "nosplash" (http://msdn.microsoft.com/ru-ru/library/ms162825(SQL.100).aspx).


8. Отключите автосохранение в реестре (ключ AutoRecover Enabled), ибо SSMS фоново сохраняет информацию ( HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\100\Tools\Shell\General\AutoRecover ).

9. Определите значения переменных %vsspv_visualstudio_dir% и %vsspv_vs_install_directory% , либо в реестре явно укажите пути для параметров DefaultSettingsDirectory и LastResetSettings ( HKCU\Software\Microsoft\Microsoft SQL Server\100\Tools\Shell\Profile ).
Например:
"%USERPROFILE%\My Documents\SQL Server Management Studio\Projects"
и
"%USERPROFILE%\Мои документы\SQL Server Management Studio\Common7\IDE\Profiles\sqlshell.vssettings"
соответственно.


10. Сам не пробовал, но рекомендуют заменить видеокарту, возможно, это поможет, если ни один из пунктов выше не решил ваших проблем.

Tags: , , ,

SQL Server

Мой SQL Server отличный переводчик

by Alexey Knyazev 17. марта 2010 09:42

Совсем недавно у меня появилась безумная идея: как организовать автоматический перевод текстов внутри сервера БД.

Возможно, это глупо перекладывать такую логику и задачу на SQL Server, т.к. он предназначен совсем для других целей...но, согласитесь, как было бы здорово, если бы наш сервер сам переводил наши данные на другой язык либо динамически либо по расписанию, пусть даже это будет машинный перевод. Прежде чем приступить к реализации этого безумия, я стал искать какие переводчики доступны в сети, главные критери: бесплатный и более или менее читабельный перевод.

Мой выбор пал на переводчик Microsoft® Translator (http://www.microsofttranslator.com/)

 

 

 

 На странице этого переводчика есть возможность переводить тексты on-line:

 

Но самое главное, что Microsoft предлагает богатый набор инструментов для интеграции переводчика в наши системы (http://www.microsofttranslator.com/Tools/)

 

Microsoft Translator Interactive SDK (http://sdk.microsofttranslator.com/) содержит примеры, как можно работать с этим инструментом:

 

Меня интересует SOAP Interface, пару месяцев назад я писал, как можно работать с Web-службами через CLR (http://www.t-sql.ru/post/WebCLR.aspx), но прежде чем начать писать сборку для перевода текстов внутри БД, необходимо зарегистрировать (если вы ещё этого не сделали) AppID (http://www.bing.com/developers/createapp.aspx), который открывает вам доступ к богатому набору инструментов, в том числе и доступ к Microsoft Translator.

После регистрации и активации AppID, можем переходить к разработке нашей сборки, примеры работы с Web-службой описаны на странице Microsoft Translator Interactive SDK.

Для начала создадим прокси-сборку, для этого необходимо выполнить команду:

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\wsdl.exe" /o:Translator.cs /n:WS http://api.microsofttranslator.com/V1/Soap.svc

Для удобства, я создал отдельную папку C:\Translator, и в ней создал BAT-ник с этой командой. После запуска этого батника в папке появился файл Translator.cs.

Теперь создадим наш класс, из которого будет сделана наша сборка: TranslatorCLR.cs

using System;
using Microsoft.SqlServer.Server;
using System.Data;
using System.Data.SqlTypes;
using System.Collections;
using WS;

public class WSClass
{
  	[SqlFunction(FillRowMethodName = "FillRow",
        	TableDefinition = "Lng nvarchar(10), Language nvarchar(100)")
    	]

//Получаем список доступных языков
public static IEnumerable GetLanguages(String AppID, string locale)
{
	ArrayList Rows = new ArrayList();
        WS.Soap lsc = new WS.Soap();
	string[] s1=lsc.GetLanguages(AppID);
	string[] s2=lsc.GetLanguageNames(AppID, locale);

	for(int i = 0; i<=s1.Length-1; i++)
	{
	Rows.Add(new object[] {s1[i], s2[i]});
	}

        return Rows;
}

public static void FillRow(
                        Object row,
                        out string Lng, out string Language)
{
	object[] xrow = (object[])row;
	Lng = (string)xrow[0];
	Language = (string)xrow[1];
}

//Перевод текста
public static string Translate(String AppID, string InputStr, string forLanguage, string toLanguage)
{

        WS.Soap lsc = new WS.Soap();
	string s=lsc.Translate(AppID, InputStr, forLanguage, toLanguage);
        return s;
}

//Определение на каком языке текст
public static string Detect(String AppID, string InputStr)
{

        WS.Soap lsc = new WS.Soap();
	string s=lsc.Detect(AppID, InputStr);
        return s;
}

}

Теперь на базе 2х классов можем создать нашу сборку, для этого создаю ещё один батник с кодом

"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CSC" /target:library /out:TranslatorWS.dll *.cs

На выходе получаем библиотеку TranslatorWS.dll.

Последний шаг-создаём сборку сериализации XML для типов в нашей сборке, для этого я опять делаю батник с текстом:

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sgen.exe" /a:TranslatorWS.dll

На выходе ещё одна библиотека: TranslatorWS.XmlSerializers.dll

Теперь регистрируем наши сборки в БД, создаём функции и начинаем работать:

CREATE DATABASE TestDB
GO

ALTER DATABASE TestDB SET TRUSTWORTHY ON
GO

USE TestDB
GO

CREATE ASSEMBLY ClrWebServices
FROM 'C:\Translator\TranslatorWS.dll'
WITH PERMISSION_SET = UNSAFE;
GO

CREATE ASSEMBLY [ClrWebServices.XmlSerializers]
FROM 'C:\Translator\TranslatorWS.XmlSerializers.dll'
WITH PERMISSION_SET = SAFE;
GO

CREATE FUNCTION [dbo].[GetLanguages]
(
@AppID nvarchar(40),
@locale nvarchar(10)
)
RETURNS TABLE
(
Lng nvarchar(10),
Language nvarchar(100)
)
AS
EXTERNAL NAME [ClrWebServices].[WSClass].[GetLanguages]
GO

CREATE FUNCTION [dbo].[Translate]
(
@AppID nvarchar(40),
@InputStr nvarchar(max),
@forLanguage nvarchar(5),
@toLanguage nvarchar(5)
)
RETURNS nvarchar(MAX)
AS
EXTERNAL NAME [ClrWebServices].[WSClass].[Translate]
GO

CREATE FUNCTION [dbo].[Detect]
(
@AppID nvarchar(40),
@InputStr nvarchar(max)
)
RETURNS nvarchar(MAX)
AS
EXTERNAL NAME [ClrWebServices].[WSClass].[Detect]
GO

Для начала получим список доступных языков:

SELECT * from [dbo].[GetLanguages] ('****************************', 'ru')

Где вместо звёздочек вы указываете ваш AppID, а 2ой параметр-это язык на которов вы хотите получить описание доступных языков, на выходе вот такая табличка:

  1. ar арабский
  2. bg болгарский
  3. zh-CHS китайский упрощенный
  4. zh-CHT китайский традиционный
  5. cs чешский
  6. da датский
  7. nl нидерландский
  8. en английский
  9. ht Гаитянский
  10. fi финский
  11. fr французский
  12. de немецкий
  13. el греческий
  14. he иврит
  15. hu венгерский
  16. it итальянский
  17. ja японский
  18. ko корейский
  19. lt литовский
  20. no норвежский
  21. pl польский
  22. pt португальский
  23. ro румынский
  24. ru русский
  25. sk словацкий
  26. sl словенский
  27. es испанский
  28. sv шведский
  29. th тайский
  30. tr турецкий

На момент написания этого поста, было доступно 30 языков.

Следующим примером я покажу, как определить на каком языке текст, для этого создам таблицу с 2мя записями на русском и английском и запустим нашу функцию:

DECLARE @s TABLE (val varchar(max))
INSERT INTO @s
SELECT 'Enter some text for the language you want detected'
UNION ALL
SELECT 'Шла Cаша по шоссе'

SELECT *, [dbo].[Detect]('****************************', val) FROM @s

Результат:

 

Ну и собственно, сам перевод данных:

DECLARE @s nvarchar(max)
SET @s='With upcoming release of the latest version of Microsoft SQL Server, SQL Server 2008 R2, Microsoft continues to build on the Information Platform Vision by enabling businesses to deliver near real-time information through rich applications. Not only does SQL Server offers a complete approach to managing, accessing and delivering information across the organization; but now the power of SQL Server is extending to the Cloud through SQL Azure. SQL Azure provides a consistent program model and common tools while offering new business opportunities, high availability, and massive scale through distributed data services.
People are at the center of the Information Platform – IT and Database professionals who support the expanding needs of the business, Developers who build solutions quickly to capture business opportunities and End users who are looking to quickly mine volumes of data for business insights. SQL Server 2008 R2 delivers something unique and empowering to each of these contributors.
'

SELECT [dbo].[Translate] ('****************************', @s, 'en', 'ru')

Результат перевода можете оценить сами:

С предстоящем выпуске последней версии Microsoft SQL Server, SQL Server 2008 R2, Майкрософт продолжает опираться на информационной платформы видение, позволяя предприятиям для доставки вблизи реального времени информацию с помощью многофункциональных приложений. Не только делает SQL Server предлагает полный подход к управлению, доступ к и доставки информации по организации; но теперь власть SQL Server расширение в облаке через SQL лазурь. Лазурный SQL предоставляет модель последовательной программы и общие инструменты предлагая новые бизнес-возможности, высокая доступность и массовом масштабе путем распределенных данных услуг. Люди, в центре платформы информации – база данных и ИТ специалистов, которые поддерживают расширение потребностей бизнеса, разработчики, которые создают решения быстро захватить бизнес-возможности и конечных пользователей, которые хотят быстро шахты объемы данных для бизнес-идеи. SQL Server 2008 R2 обеспечивает что-то уникальное и расширение прав и возможностей для каждого из этих вкладчиков..

Tags: , , , ,

SQL Server

Своё шифрование в SQL Server 2005 и выше

by Alexey Knyazev 9. марта 2010 08:57

Практически в любой отрасли существуют свои критические данные, которые требуют шифрования. Начиная с SQL сервера версии 6.x, для шифрования данных вы можете применять функцию ENCRYPT (в последних версия эта функция уже недоступна), которая использует тот же метод (шифрования), что и опция WITH ENCRYPTION.

Начиная с SQL Server 2000 появилась недокументированная функция PWDENCRYPT, которая возвращает Хэш пароля (PWDENCRYPT — это устаревшая функция, которая может не поддерживаться в будущих версиях SQL Server. Вместо этого используйте программу HASHBYTES. HASHBYTES предоставляет больше алгоритмов хэширования), а так же PWDCOMPARE - Хэширует пароль и сравнивает хэш с хэшем существующего пароля.

Для более сложного шифрования данных до версии SQL Server 2005 приходилось "изобретать велосипед", но начиная с 9ой версии шифрование и дешифровка стали встроенным функционалом. А в SQL Server 2008 появилось прозрачное шифрование.

Но в очередной раз попробуем изобрести велосипед и организовать своё шифрование данных в виде CLR-сборки.

В качестве алгоритма шифрования я использую RSA. Алгоритм используется в большом числе криптографических приложений. На 2009 год система шифрования на основе RSA считается надёжной, начиная с размера в 1024 бита.

За основу взят класс RSACryptoServiceProvider.

Код сборки на C#:

using System;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Security.Cryptography;
using System.Text;

public class RSACLR
{
    [SqlFunction(FillRowMethodName = "FillRow",
        TableDefinition = "publicAndPrivateKeys nvarchar(max), justPublicKey nvarchar(max)")
    ]

//Генерируем 2 ключа: закрытый с публичным и только публичный
    public static IEnumerable GenerateKeys(int KeySize)
    {
        ArrayList row = new ArrayList();
        RSACryptoServiceProvider RSAProvider = new RSACryptoServiceProvider(KeySize);
        row.Add(new object[] { RSAProvider.ToXmlString(true), RSAProvider.ToXmlString(false) });
        return row;
    }

    public static void FillRow(Object row, out string publicAndPrivateKeys, out string justPublicKey)
    {

        object[] xrow = (object[])row;
        publicAndPrivateKeys = (string)xrow[0];
        justPublicKey = (string)xrow[1];

    }

//Шифрование, на входе строка, размер ключа и открытый(публичный) ключ
    public static string EncryptString(string inputString, int dwKeySize,
                             string xmlString)
    {
        RSACryptoServiceProvider rsaCryptoServiceProvider =
                                      new RSACryptoServiceProvider(dwKeySize);
        rsaCryptoServiceProvider.FromXmlString(xmlString);
        int keySize = dwKeySize / 8;
        byte[] bytes = Encoding.UTF32.GetBytes(inputString);

        int maxLength = keySize - 42;
        int dataLength = bytes.Length;
        int iterations = dataLength / maxLength;
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i <= iterations; i++)
        {
            byte[] tempBytes = new byte[
                    (dataLength - maxLength * i > maxLength) ? maxLength :
                                                  dataLength - maxLength * i];
            Buffer.BlockCopy(bytes, maxLength * i, tempBytes, 0,
                              tempBytes.Length);
            byte[] encryptedBytes = rsaCryptoServiceProvider.Encrypt(tempBytes,
                                                                      true);

            Array.Reverse(encryptedBytes);

            stringBuilder.Append(Convert.ToBase64String(encryptedBytes));
        }
        return stringBuilder.ToString();
    }

//Расшифровка, на входе шифрованная строка, размер ключа и закрытый ключ
    public static string DecryptString(string inputString, int dwKeySize,
                             string xmlString)
    {
        RSACryptoServiceProvider rsaCryptoServiceProvider
                                 = new RSACryptoServiceProvider(dwKeySize);
        rsaCryptoServiceProvider.FromXmlString(xmlString);
        int base64BlockSize = ((dwKeySize / 8 ) % 3 != 0) ?
          (((dwKeySize / 8 ) / 3) * 4) + 4 : ((dwKeySize / 8 ) / 3) * 4;
        int iterations = inputString.Length / base64BlockSize;
        ArrayList arrayList = new ArrayList();
        for (int i = 0; i < iterations; i++)
        {
            byte[] encryptedBytes = Convert.FromBase64String(
                 inputString.Substring(base64BlockSize * i, base64BlockSize));

            Array.Reverse(encryptedBytes);
            arrayList.AddRange(rsaCryptoServiceProvider.Decrypt(
                                encryptedBytes, true));
        }
        return Encoding.UTF32.GetString(arrayList.ToArray(
                                  Type.GetType("System.Byte")) as byte[]);
    }
}

Как всегда минимум кода.

Теперь регистрируем нашу сборку и создаём на её основе 3 функции (получение ключей, шифрование и расшифровка):

--Включаем выполнение пользовательских сборок
SP_CONFIGURE 'clr enabled', 1
GO
RECONFIGURE
GO

--Создаём тестовую БД для демострации
CREATE DATABASE TestDB
GO

--Модули базы данных (например, пользовательские функции или хранимые процедуры),
--которые используют контекст олицетворения, могут обращаться к ресурсам,
--находящимся вне базы данных.
ALTER DATABASE TestDB SET TRUSTWORTHY ON
GO

--Переходим в нашу БД
USE TestDB
GO

--Регистрируем сборку
CREATE ASSEMBLY RSACLR
FROM 'C:\RSA\RSACLR.dll'
WITH PERMISSION_SET = UNSAFE;
GO

--Получение ключей
CREATE FUNCTION GenerateKeys(@KeySize int)
RETURNS TABLE
(
publicAndPrivateKeys NVARCHAR(max),
justPublicKey NVARCHAR(max)
)
EXTERNAL NAME RSACLR.RSACLR.GenerateKeys;
GO

--Шифрование строки
CREATE FUNCTION EncryptString
(
@inputString nvarchar(MAX),
@dwKeySize int,
@xmlString nvarchar(MAX)
)
RETURNS nvarchar(MAX)
AS
EXTERNAL NAME RSACLR.RSACLR.EncryptString;
GO

--Расшифровка строки
CREATE FUNCTION DecryptString
(
@inputString nvarchar(MAX),
@dwKeySize int,
@xmlString nvarchar(MAX)
)
RETURNS nvarchar(MAX)
AS
EXTERNAL NAME RSACLR.RSACLR.DecryptString;
GO

Теперь продемонстрирую, как это работает:

--Создадим таблицу, в которой будут "жить" наши ключи
CREATE TABLE MyKeys(id int identity, publicAndPrivateKeys xml, justPublicKey xml)
--Добавим несколько ключей разной размерности
INSERT INTO MyKeys
SELECT * FROM GenerateKeys(512)
UNION ALL
SELECT * FROM GenerateKeys(1024)
UNION ALL
SELECT * FROM GenerateKeys(2048)

--и посмотрим в каком виде они у нас хранятся
SELECT * FROM MyKeys

Для наглядности я выбрал для хранения ключей тип XML

Теперь можно с помощью любой из пар ключей шифровать и расшифровывать данные.

--Создаём таблицу слов
CREATE TABLE MyWords(Val nvarchar(max), EncryptVal nvarchar(max))
--и наполним её данными
INSERT INTO MyWords
SELECT 'Knyazev Alexey', null
UNION ALL
SELECT 'http://www.t-sql.ru', null
UNION ALL
SELECT 'SQL Server', null

--теперь зашифруем с помощью открытого ключа
DECLARE @k nvarchar(max), @k2 nvarchar(max)
SELECT @k=convert(nvarchar(max), justPublicKey) FROM MyKeys WHERE id=1

UPDATE MyWords
SET EncryptVal=dbo.EncryptString(Val, 512, @k)

Расшифровать можно так:

DECLARE @k nvarchar(max), @k2 nvarchar(max)
SELECT @k=convert(nvarchar(max), PublicAndPrivateKeys) FROM MyKeys WHERE id=1

SELECT *, dbo.DecryptString(EncryptVal, 512, @k) FROM MyWords

Вот и весь "велосипед", цель данного примера показать, в очередной раз, как CLR-сборки могут разнообразить и улучшить работу с SQL Server.

Tags: , , , , , ,

SQL Server

Загрузка/выгрузка файлoв в/из BD (+их компрессия)

by Alexey Knyazev 2. марта 2010 08:37

У любого разработчика БД рано или поздно возникает потребность вставить файл(ы) в базу. Преимуществ хранения файлов внутри БД уйма, как и недостатков, но сегодня не об этом, а вообще о том, как возможно загрузить/выгрузить файлы. Наиболее интересный и правильный вариант, на сегодня, работы с файлами - это FileStream (появился в SQL Server 2008).

Хранилище FILESTREAM в SQL Server 2008 позволяет приложениям на основе SQL Server хранить в файловой системе неструктурированные данные, такие как документы и изображения. Приложения могут эффективно использовать многопоточные API-интерфейсы и производительность файловой системы, одновременно обеспечивая согласованность между неструктурированными и соответствующими им структурированными данными.

Но всё же до сих пор многих интересует вариант хранения файлов внутри обычных таблиц в полях BLOB (image/varbinary). Вставку файлов в БД и последующую работу с ними легко организовать с помощью нескольких строк на любом языке программирования, но мы попробуем обойтись средствами SQL Server`а.

Для начала рекомендую ознакомиться с статьёй Вставка картинки (файла) в поле таблицы и работа с Blob полями.

Начиная с SQL Server 2005 вставку файла можно сделать с помощью OPENROWSET

INSERT INTO dbo.Files (FileName, [File])
SELECT 'MyPic.bmp' AS FileName, *
FROM OPENROWSET(BULK N'C:\MyPic.bmp', SINGLE_BLOB) AS [File]

Но это только загрузка файла.

Тут же возникла идея реализовать эту задачу с помощью сборки CLR, раз нет в T-SQL стандартного решения, то расширим его самостоятельно с помощью своей сборки. Но раз уж это будит свой функционал, то я решил его дополнить ещё одной фичей…компрессия файла!!! База не резиновая!

Код достаточно легко читаем, но если вопросы останутся, то я всегда рад буду помочь, итак код сборки на C#:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.IO;
using System.IO.Compression;

public class FileCompressCLR
{
    [Microsoft.SqlServer.Server.SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]

    //Загрузка файла в виде бинарника, на входе Полный путь к файлу
    public static SqlBytes LoadFile(string FileName)
    {
        FileStream file = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read);

        MemoryStream ms = new MemoryStream();
        int sourcebyte = file.ReadByte();
        while (sourcebyte != -1)
        {
            ms.WriteByte((byte)sourcebyte);
            sourcebyte = file.ReadByte();
        }

        file.Close();
        return new SqlBytes(ms);
    }

    //Загрузка файла в виде бинарника с компрессией, на входе Полный путь к файлу
    public static SqlBytes LoadCompressFile(string FileName)
    {
        FileStream file = new FileStream(FileName, FileMode.Open, FileAccess.Read, FileShare.Read);
        byte[] buffer = new byte[file.Length];
        file.Read(buffer, 0, buffer.Length);
        file.Close();

        MemoryStream ms = new MemoryStream();

        DeflateStream compress = new DeflateStream(ms, CompressionMode.Compress, true);
        compress.Write(buffer, 0, buffer.Length);

        compress.Close();
        compress = null;

        return new SqlBytes(ms);
    }

    //Выгрузка файла в указанный источник
    public static string SaveFile(string FileName, SqlBytes CompressedFile)
    {
        if (CompressedFile.IsNull)
            return "Error";

        try
        {

            FileStream file = File.Create(FileName);

            int sourcebyte = CompressedFile.Stream.ReadByte();
            while (sourcebyte != -1)
            {
                file.WriteByte((byte)sourcebyte);
                sourcebyte = CompressedFile.Stream.ReadByte();
            }

            file.Close();
        }

        catch (Exception)
        {
            return "Error";
        }

        return "OK";
    }

    //Выгрузка файла в указанный источник с предварительной декомпрессией
    public static string SaveDecompressFile(string FileName, SqlBytes CompressedFile)
    {
        if (CompressedFile.IsNull)
        return "Error";

        DeflateStream decompress = new DeflateStream(CompressedFile.Stream, CompressionMode.Decompress, true);

        try
        {

            FileStream file = File.Create(FileName);

            int sourcebyte = decompress.ReadByte();
            while (sourcebyte != -1)
            {
                file.WriteByte((byte)sourcebyte);
                sourcebyte = decompress.ReadByte();
            }

            file.Close();
        }

        catch (Exception)
        {
            return "Error";
        }

        finally
        {
            decompress.Close();
            decompress = null;
        }    

        return "OK";
    }
}

Компилируем код и сохраняем библиотеку в папку C:\CLR.

Теперь включаем на сервере возможность работы с CLR, создаём тестовую БД, регистрируем сборку на сервере БД, создаём 4 функции для работы с файлами:

--Включаем выполнение пользовательских сборок
SP_CONFIGURE 'clr enabled', 1
GO
RECONFIGURE
GO

--Создаём тестовую БД для демострации
CREATE DATABASE TestDB
GO

--Модули базы данных (например, пользовательские функции или хранимые процедуры),
--которые используют контекст олицетворения, могут обращаться к ресурсам,
--находящимся вне базы данных.
ALTER DATABASE TestDB SET TRUSTWORTHY ON
GO

--Переходим в нашу БД
USE TestDB
GO

--Регистрируем сборку
CREATE ASSEMBLY FileCompressCLR
FROM 'C:\CLR\FileCompressCLR.dll'
WITH PERMISSION_SET = UNSAFE;
GO

--Создаём функцию загрузки обычного файла
CREATE FUNCTION [LoadFile]
(
@FileName nvarchar(MAX)
)
RETURNS varbinary(MAX)
AS
EXTERNAL NAME [FileCompressCLR].[FileCompressCLR].[LoadFile];
GO

--Создаём функцию загрузки файла + его компрессия
CREATE FUNCTION [LoadCompressFile]
(
@FileName nvarchar(MAX)
)
RETURNS varbinary(MAX)
AS
EXTERNAL NAME [FileCompressCLR].[FileCompressCLR].[LoadCompressFile];
GO

--Создаём функцию выгрузки обычного файла
CREATE FUNCTION [SaveFile]
(
@FileName nvarchar(MAX),
@CompressedFile varbinary(MAX)
)
RETURNS nvarchar(10)
AS
EXTERNAL NAME [FileCompressCLR].[FileCompressCLR].[SaveFile];
GO

--Создаём функцию выгрузки сжатого файла
CREATE FUNCTION [SaveDecompressFile]
(
@FileName nvarchar(MAX),
@CompressedFile varbinary(MAX)
)
RETURNS nvarchar(10)
AS
EXTERNAL NAME [FileCompressCLR].[FileCompressCLR].[SaveDecompressFile];
GO

Всё, мы расширили возможности нашего SQL Server`a. Теперь покажу, как работать с этими функциями.

Для начала посмотрим, разницу в размере бинарника, который мы загружаем (в качестве демонстрации использую файл библиотеки CLR):

SELECT
datalength(dbo.LoadFile('C:\CLR\FileCompressCLR.dll')) FileSize,
datalength(dbo.LoadCompressFile('C:\CLR\FileCompressCLR.dll')) CompressFileSize

Результат не может не радовать (сжатый файл в 2 раза меньше):

5632 против 2900

Теперь пример, как вставить в БД сразу несколько файлов:

--Создаём таблицу для демонстрации массовой вставки
CREATE TABLE Files
(
id int identity,
FileName nvarchar(max),
[File] varbinary (max) default null,
CompressFile varbinary(max) default null
)

--Вставка только названий с файлами
INSERT INTO Files (FileName)
SELECT 'C:\CLR\FileCompressCLR.dll'
UNION ALL
SELECT 'C:\CLR\Winter.jpg'
UNION ALL
SELECT 'C:\CLR\Test.txt'

--Загружаем сами бинарники
UPDATE Files
SET
[File]=dbo.LoadFile(FileName),
[CompressFile]=dbo.LoadCompressFile(FileName)

Покажу как выглядит таблица:

 

Теперь удалим из папки все файлы, которые были загружены в таблицу, и попробуем их вытащить из БД

SELECT FileName,
dbo.SaveFile(replace(FileName, '.','1.'), [File]),
dbo.SaveDecompressFile(replace(FileName, '.','2.'), CompressFile)
FROM Files

Для различия файлов я в качестве имени, под которым сохраняется файл на диске, подставляю в имя суффиксы 1 и 2 ( replace(FileName, ‘.’,'1.’) )

Файлы появились и они полностью рабочии!

Tags: , , , , ,

SQL Server

Читаем почту (IMAP). CLR-сборка.

by Alexey Knyazev 4. февраля 2010 08:22

В одной из предыдущих статей я писал, как читать почту в SQL Server 2005/2008/2008R2 по протоколу POP3 (http://www.t-sql.ru/post/POP3CLR.aspx), там же пообещал, что в ближайшее время покажу, как осуществлять доступ к почте по протоколу IMAP.

Область применения протокола IMAP ( Internet Message Access Protocol ) аналогична области применения протокола POP3: он тоже предназначен для получения почты и используется на участке между MUA получателя и хранилищем сообщений. IMAP предоставляет более широкие возможности работы с почтовыми ящиками, чем POP3: он позволяет работать с несколькими почтовыми ящиками на одном или нескольких серверах IMAP как с файлами и каталогами на собственной машине пользователя. Обычно почтовые ящики сервера IMAP действительно представляют собой файлы в специальном каталоге сервера и его подкаталогах.

Как и в прошлый раз - это будит CLR-сборка (работает достаточно шустро). Но прежде рекомендую ознакомиться с описанием IMAP-протокола.

Полный перечень всех команд, а так же описание протокола можно прочитать в Запросе комментариев (англ. Request for Comments, RFC) — документ из серии пронумерованных информационных документов Интернета, содержащих технические спецификации и Стандарты.

RFC 3501 (IMAP версии 4 издание 1 (IMAP4rev1)), он заменил RFC 2060 (IMAP версии 4 (IMAP4)). Русскую версию спецификации так же легко найти в РУ-нете (http://opds.sut.ru/electronic_manuals/mail/5_IMAP.htm, http://book.itep.ru/4/44/imap4443.htm)

Сервер IMAP ожидает соединения от клиентов на порту TCP 143. После установления соединения сервер посылает свое приветствие клиенту, и начинается диалог, в котором клиент посылает серверу команды, а сервер сообщает о результатах их выполнения или присылает затребованную клиентом информацию. Как и сеанс POP3, сеанс IMAP делится на несколько состояний ( states ). Допустимый набор команд зависит от текущего состояния сеанса. Сеанс может находиться в одном из следующих состояний:

  • -неаутентифицированное состояние (Not Authenticated State): клиент должен пройти процедуру аутентификации прежде, чем сможет выполнять большинство команд;
  • -аутентифицированное состояние (Authenticated State): клиент аутентифицирован и должен выбрать почтовый ящик, прежде чем сможет работать с отдельными сообщениями;
  • -выбранное состояние (Selected State): почтовый ящик выбран;
  • -состояние выхода (Logout State): сеанс завершается.

 

 

Переходы, обозначенные цифрами:

  1. соединение без предварительной аутентификации;
  2. соединение с предварительной аутентификацией;
  3. отвергнутое соединение;
  4. успешная аутентификация;
  5. успешное выполнение команды SELECT или EXAMINE;
  6. команда CLOSE или неудачное завершение команды SELECT или EXAMINE;
  7. команда LOGOUT или потеря связи.

Сами Команды клиента и ответы сервера IMAP я в этой статье описывать не буду, так как вы сами при желании сможете с ними ознакомиться по ссылкам выше, а сразу приведу код сборки:

using System;
using Microsoft.SqlServer.Server;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;

public class IMAPClr
{
    private static TcpClient IMAP;
    private static NetworkStream ns;
    private static StreamWriter sw;
    private static StreamReader sr;

    [SqlFunction]  

//Выводим кол-во писем
    public static int MailCount(string Host, string User, string Password)
    {

        string s = Connect(Host, 143);
        if (s.Substring(0, 4) != "* OK")
        {
            return -1;
        }

        s = Authenticate(User, Password);
        if (s.Substring(0, 4) != "$ OK")
        {
            return -2;
        }

        sw.WriteLine("$ LOGIN " + User + " " + Password);
        sw.Flush();
        Response();

        sw.WriteLine("$ STATUS INBOX (messages)");
        sw.Flush();

        string res = Response();
        Match m = Regex.Match(res, "[0-9]*[0-9]");

        Disconnect();
        return Convert.ToInt32(m.ToString());

    }

//Кол-во непрочитанных писем
    public static int MailUnreadCount(string Host, string User, string Password)
    {

        string s = Connect(Host, 143);
        if (s.Substring(0, 4) != "* OK")
        {
            return -1;
        }

        s = Authenticate(User, Password);
        if (s.Substring(0, 4) != "$ OK")
        {
            return -2;
        }

        sw.WriteLine("$ LOGIN " + User + " " + Password);
        sw.Flush();
        Response();

        sw.WriteLine("$ STATUS INBOX (unseen)");
        sw.Flush();

        string res = Response();
        Match m = Regex.Match(res, "[0-9]*[0-9]");

        Disconnect();
        return Convert.ToInt32(m.ToString());

    }

    [SqlFunction(FillRowMethodName = "FillRowHeaders"
    , TableDefinition = "MessageID int, MessageHeader nvarchar(max)")]

//Заголовки
    public static IEnumerable GetMessagesHeaders(string Host, string User, string Password, int MessageStart, int MessageEnd)
    {
        ArrayList rows = new ArrayList();

        string s = Connect(Host, 143);
        if (s.Substring(0, 4) != "* OK")
        {
            rows.Add(new object[] { -1, s });
            return rows;
        }

        s = Authenticate(User, Password);
        if (s.Substring(0, 4) != "$ OK")
        {
            rows.Add(new object[] { -2, s });
            return rows;
        }

        SelectInbox();

        while (MessageStart <= MessageEnd)
        {
            rows.Add(new object[] { MessageStart, GetMessageHeaders(MessageStart).ToString() });
            MessageStart += 1;
        }
        Disconnect();
        return rows;
    }

    public static void FillRowHeaders(Object row, out int MessageID, out string MessageHeader)
    {

        object[] xrow = (object[])row;
        MessageID = (int)xrow[0];
        MessageHeader = (string)xrow[1];

    }

    [SqlFunction(FillRowMethodName = "FillRowMessages"
    , TableDefinition = "MessageID int, Message nvarchar(max)")]

//Тело письма
    public static IEnumerable GetMessages(string Host, string User, string Password, int MessageStart, int MessageEnd)
    {
        ArrayList rows = new ArrayList();

        while (MessageStart <= MessageEnd)
        {
            string s = Connect(Host, 143);
            if (s.Substring(0, 4) != "* OK")
            {
                rows.Add(new object[] { -1, s });
                return rows;
            }

            s = Authenticate(User, Password);
            if (s.Substring(0, 4) != "$ OK")
            {
                rows.Add(new object[] { -2, s });
                return rows;
            }
            SelectInbox();
            rows.Add(new object[] { MessageStart, GetMessage(MessageStart).ToString()});
            Disconnect();
            MessageStart += 1;
        }

        return rows;
    }

    public static void FillRowMessages(Object row, out int MessageID, out string Message)
    {

        object[] xrow = (object[])row;
        MessageID = (int)xrow[0];
        Message = (string)xrow[1];
    }

//Подключение к IMAP-серверу
    private static string Connect(string Host, int port)
    {
        try
        {
            IMAP = new TcpClient(Host, port);
            ns = IMAP.GetStream();
            sw = new StreamWriter(ns);
            sr = new StreamReader(ns);
            return Response();
        }
        catch (SocketException ex)
        {
            return ex.Message;
        }
    }

//Отключаемся от сервера
    public static void Disconnect()
    {
        sw.WriteLine("$ LOGOUT");
        sw.Flush();
        IMAP.Close();
    }

//Идентификация пользователя
    public static string Authenticate(string User, string Password)
    {
        sw.WriteLine("$ LOGIN " + User + " " + Password);
        sw.Flush();
        return Response();
    }

//Открываем доступ к указанному почтовому ящику
    public static string SelectInbox()
    {
        sw.WriteLine("$ EXAMINE INBOX");
        sw.Flush();
        return Response();
    }

//Заголовок письма по его номеру
    public static object GetMessageHeaders(int index)
    {
        sw.WriteLine("$ FETCH " + index + " (body[header.fields (from subject date)])");
        sw.Flush();

        return Response();
    }

//Письмо по номеру
    public static object GetMessage(int index)
    {

        sw.WriteLine("$ FETCH " + index + " body[text]");
        sw.Flush();

        return Response();
    }

    private static string Response()
    {
        byte[] data = new byte[IMAP.ReceiveBufferSize];
        int ret = ns.Read(data, 0, data.Length);
        return Encoding.ASCII.GetString(data).TrimEnd();
    }

}

Если у Вас возникнут вопросы по коду, то буду рад ответить в комментариях к этой статье.

Далее регистрируем сборку и создаём набор T-SQL функций для работы с ней:

--Регистрируем сборку
CREATE ASSEMBLY ClrIMAP
FROM 'C:\IMAP\IMAPClr.dll'
WITH PERMISSION_SET = UNSAFE;
GO

--Функция выводит кол-во писем в ящике
CREATE FUNCTION [dbo].[MailCount]
(
@Host nvarchar(255),
@User nvarchar(255),
@Password nvarchar(255)
)
RETURNS [int] WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [ClrIMAP].[IMAPClr].[MailCount]
GO

--Функция с кол-ом непрочитанных писем
CREATE FUNCTION [dbo].[MailUnreadCount]
(
@Host nvarchar(255),
@User nvarchar(255),
@Password nvarchar(255)
)
RETURNS [int] WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [ClrIMAP].[IMAPClr].[MailUnreadCount]
GO

--Функция чтения заголовков писем
CREATE FUNCTION [dbo].[GetMessagesHeaders]
(
@Host nvarchar(255),
@User nvarchar(255),
@Password nvarchar(255),
@MessageStart int,
@MessageEnd int
)
RETURNS TABLE
(
MessageID INT,
MessageHeader NVARCHAR(max)
)
EXTERNAL NAME [ClrIMAP].[IMAPClr].[GetMessagesHeaders];
GO

--Функция чтения самого письма (писем)
CREATE FUNCTION [dbo].[GetMessages]
(
@Host nvarchar(255),
@User nvarchar(255),
@Password nvarchar(255),
@MessageStart int,
@MessageEnd int
)
RETURNS TABLE
(
MessageID INT,
Message NVARCHAR(max)
)
EXTERNAL NAME [ClrIMAP].[IMAPClr].[GetMessages];
GO

Пара примеров работы с этими функциями:

--Выводим кол-во писем на сервере (всего и новых)
select
[dbo].[MailCount] ('imap.MailServer.ru', 'MyMail@MailServer.ru', 'MyPassword') as MailCount,
[dbo].[MailUnreadCount] ('imap.MailServer.ru', 'MyMail@MailServer.ru', 'MyPassword') as MailUnreadCount

--Выводим 5 первых писем и их заголовки (от кого, дата, тема)
select t1.MessageID, t1.MessageHeader, t2.Message from
[dbo].[GetMessagesHeaders] ('imap.MailServer.ru', 'MyMail@MailServer.ru', 'MyPassword', 1, 5) t1
inner join
[dbo].[GetMessages] ('imap.MailServer.ru', 'MyMail@MailServer.ru', 'MyPassword', 1, 5) t2
on t1.MessageID=t2.MessageID

Пример результата:

 

Tags: , , , , , ,

SQL Server

Отправка SMS через Web-сервис (CLR)

by Alexey Knyazev 18. января 2010 22:00

Кратко суть задачи: ГАРАНТИРОВАННАЯ отправка СМС-сообщений из уже существующих информационных систем, которые используются у нас на предприятии. Первое, что пришло в голову-это отправка через почту (e-mail to SMS) на ящик вида [номер абонента]@[адрес оператора] большинство сотовых операторов предоставляют подобную услугу (например у МТС: 7913ххххххх@sms.mtslife.ru), хоть и не гарантируют 100% доставку всех сообщений таким образом. После того, как объём сообщений, который стал генерить наш сервер, стал достаточно большим, часть сообщений стали "пропадать" либо приходить с большими задержками. Пришлось искать другое решение.

Идеальный вариант - это работа на прямую c СМС-сервером оператора по протоколу SMPP, но это дополнительная головная боль в виде подписания договора с операторами, которые предоставляют такую возможность для корпоративных клиентов и скорее всего - это дорогая услуга.

В качестве ещё одного варианта был поиск посредников, которые предоставляют подобные услуги. Выбор пал на ресурс http://sms-host.ru (не сочтите за рекламу). Они гарантируют доставку и отслеживание состояния СМС-сообщений через Веб сервис, но ПЛАТНО. Ну да ладно, попросили у них тестовый доступ и я сразу же загорелся идеей сделать CLR-сборку для работы с Веб сервисом.

Адрес Веб-сервиса: https://sms-host.ru/service/smshostws.asmx?WSDL.

Описание классов: http://www.sms-host.ru/docs/.

 

SumbitSm

Отправляет коллекцию одиночных сообщений

Test
The test form is only available for requests from the local machine.
SOAP 1.1
The following is a sample SOAP 1.1 request and response. The placeholders shown need to be replaced with actual values.

POST /service/smshostws.asmx HTTP/1.1
Host: sms-host.ru
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://sms-host.ru/SumbitSm"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <Authentication xmlns="http://sms-host.ru/">
      <User>string</User>
      <Password>string</Password>
    </Authentication>
  </soap:Header>
  <soap:Body>
    <SumbitSm xmlns="http://sms-host.ru/">
      <messageList>
        <WsSubmitSm ValidityPeriodSmpp="string" MessageText="string" SenderAddress="string" ReceiverAddress="string" MessageId="guid" />
        <WsSubmitSm ValidityPeriodSmpp="string" MessageText="string" SenderAddress="string" ReceiverAddress="string" MessageId="guid" />
      </messageList>
    </SumbitSm>
  </soap:Body>
</soap:Envelope>
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <SumbitSmResponse xmlns="http://sms-host.ru/">
      <SumbitSmResult>
        <WsSubmitSmResp ErrorDescription="string" ErrorCode="int" PartCount="unsignedByte" MessageId="guid" />
        <WsSubmitSmResp ErrorDescription="string" ErrorCode="int" PartCount="unsignedByte" MessageId="guid" />
      </SumbitSmResult>
    </SumbitSmResponse>
  </soap:Body>
</soap:Envelope>

 

QuerySm

Возвращает состояние сообщений, ранее отправленных с помощью метода SumbitSm

Test
The test form is only available for requests from the local machine.
SOAP 1.1
The following is a sample SOAP 1.1 request and response. The placeholders shown need to be replaced with actual values.

POST /service/smshostws.asmx HTTP/1.1
Host: sms-host.ru
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://sms-host.ru/QuerySm"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <Authentication xmlns="http://sms-host.ru/">
      <User>string</User>
      <Password>string</Password>
    </Authentication>
  </soap:Header>
  <soap:Body>
    <QuerySm xmlns="http://sms-host.ru/">
      <messageList>
        <WsQuerySm MessageId="guid" />
        <WsQuerySm MessageId="guid" />
      </messageList>
    </QuerySm>
  </soap:Body>
</soap:Envelope>
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <QuerySmResponse xmlns="http://sms-host.ru/">
      <QuerySmResult>
        <WsQuerySmResp EndTime="dateTime" BeginTime="dateTime" PartErrorCount="unsignedByte" PartDeliveredCount="unsignedByte" PartSendCount="unsignedByte" StateName="string" StateCode="int" MessageId="guid" />
        <WsQuerySmResp EndTime="dateTime" BeginTime="dateTime" PartErrorCount="unsignedByte" PartDeliveredCount="unsignedByte" PartSendCount="unsignedByte" StateName="string" StateCode="int" MessageId="guid" />
      </QuerySmResult>
    </QuerySmResponse>
  </soap:Body>
</soap:Envelope>

Как видно из документации, задача более чем тривиальная.

Приступим:

1) Создадим папку C:\SMS

2) Создаём прокси-сборку, запустив "

C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\wsdl.exe" /o:SMSHost.cs /n:WS https://sms-host.ru/service/smshostws.asmx?WSDL

На выходе у нас получился файл SMSHost.cs

3) Немного изучив Веб-сервис, пишем нашу сборку, с 2мя функциями-отправка смс и получение состояния отправленного сообщения:

using System;
using Microsoft.SqlServer.Server;
using WS;

public class WSClass
{
            [SqlFunction]

    public static int SendMessage(string User, string Password, string SenderAddress, string ReceiverAddress, Guid MessageID, string ValidityPeriodSmpp, string Message)
    {

	WS.Authentication auth = new WS.Authentication();
            auth.User = User;
            auth.Password = Password;

	WS.WsSubmitSm s = new WS.WsSubmitSm();
            s.SenderAddress = SenderAddress;
            s.ReceiverAddress = ReceiverAddress;
	    s.MessageId = MessageID;
            s.ValidityPeriodSmpp = ValidityPeriodSmpp;
            s.MessageText = Message;

            WS.WsSubmitSm[] ss = new WS.WsSubmitSm[1];
            ss[0] = s;

	WS.SmsHostWs SendSMS=new WS.SmsHostWs();
	SendSMS.AuthenticationValue=auth;

	WS.WsSubmitSmResp Resp=new WS.WsSubmitSmResp();
	Resp=SendSMS.SumbitSm(ss)[0];

	return Resp.ErrorCode;
    }

  public static string MessageState(string User, string Password, Guid MessageID)
    {

	WS.Authentication auth = new WS.Authentication();
        auth.User = User;
        auth.Password = Password;

	WS.WsQuerySm q=new WS.WsQuerySm();
	q.MessageId=MessageID;

	WS.WsQuerySm[] qq = new WS.WsQuerySm[1];
        qq[0] = q;

	WS.SmsHostWs SendSMS=new WS.SmsHostWs();
	SendSMS.AuthenticationValue=auth;

	WS.WsQuerySmResp[] Resp = new WS.WsQuerySmResp[1];
        Resp[0]=SendSMS.QuerySm(qq)[0];

	return Resp[0].StateName;
    }

}

Сохраним этот текст в нашей папке в файл MyCLR.cs

4) Компилируем нашу библиотеку:

"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CSC" /target:library /out:WSSMSHost.dll *.cs

На выходе файл WSSMSHost.dll

5) Создаем сборку сериализации XML:

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sgen.exe" /a:WSSMSHost.dll

На выходе файл WSSMSHost.XmlSerializers.dll

Вроде бы ВСЁ. Дальше регистрируем наши библиотеки и пробуем отправить сообщения/прочитать их состояние.

CREATE ASSEMBLY ClrSMSHost
FROM 'C:\SMS\WSSMSHost.dll'
WITH PERMISSION_SET = UNSAFE;
GO

CREATE ASSEMBLY [ClrSMSHost.XmlSerializers]
FROM 'C:\SMS\WSSMSHost.XmlSerializers.dll'
WITH PERMISSION_SET = SAFE;
GO

Создаём функции:

CREATE FUNCTION [dbo].[SendMessage]
(
@User nvarchar(255),
@Password nvarchar(255),
@SenderAddress nvarchar(255),
@ReceiverAddress nvarchar(255),
@MessageID uniqueidentifier,
@ValidityPeriodSmpp nchar(16),
@Message nvarchar(max)
)
RETURNS [int] WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [ClrSMSHost].[WSClass].[SendMessage]
GO

CREATE FUNCTION [dbo].[MessageState]
(
@User nvarchar(255),
@Password nvarchar(255),
@MessageID uniqueidentifier
)
RETURNS [nvarchar](max) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [ClrSMSHost].[WSClass].[MessageState]
GO

А теперь покажу как работать с этими функциями:

--Таблица для тестов
create table MyTable (MyID uniqueidentifier, Phone char(11), MyMessage nvarchar(50))
--Вставим всего 2 записи, для демонстрации
insert into MyTable
select NewID(), '7904ххххххх', 'Message1'
union all
select NewID(), '7904ххххххх', 'Message2'

Ну и отправим сообщения:

select  MyID, MyMessage, [dbo].[SendMessage] ('MyUser', 'MyPassword', 'SMS-Host.ru',
Phone, MyID, '000002233429000R', MyMessage)
from MyTable

где 'MyUser', 'MyPassword' - это логин и пароль на доступ к Веб сервису, а '000002233429000R' - время жизни сообщения (Время, в течение которого сервер будет пытаться отправить сообщение, если получатель недоступен. Если по истечении времени жизни сообщение все еще не доставлено, попытки доставки прекращаются и сообщение считается недоставленным.

Сообщение может стать недоставленным и до истечения времени жизни, если соответствующие сервисы оператора связи сообщили о невозможности доставки (например, номер получателя не существует). По умолчанию время жизни сообщения 2 суток с момента первой попытки отправки.), Для данного поля допустим только интервальный формат времени, то есть в форме YYMMDDhhmmsstnnR - Формат времени в стандарте SMPP v3.4.

Результат запроса: 

  1. BF23FCC4-00DD-4309-BF5A-AC4CAA22160E Message1 0
  2. 97063992-182E-4816-B648-35B8AE6FFBAE Message1 0

В ответе на запрос каждый элемент содержит атрибут ErrorCode Коды ошибок подразделяются на следующие категории:

Диапазон значений Категория

  • 0 Ошибок нет
  • 1-10 Текст сообщения не прошел проверку
  • 11-20 Номер получателя не прошел проверку
  • 21-30 Номер отправителя не прошел проверку
  • 31-40 Ошибки при постановке в очередь на отправку (например, если сообщение с таким идентфикатором уже отправлялось)

Отслеживать состояние сообщений можно запросом:

select MyID, [dbo].[MessageState] ('MyUser', 'MyPassword', MyID)
from MyTable

Результат запроса:

BF23FCC4-00DD-4309-BF5A-AC4CAA22160E	Сообщение доставлено
97063992-182E-4816-B648-35B8AE6FFBAE	Сообщение доставлено

 

Таким образом, практически на коленке, реализована задача…надеюсь кому-то этот пост будет полезен. Если у вас возникнут вопросы, то буду рад вам помочь.

Tags: , , , , , ,

SQL Server

Работа с Web-службами через CLR

by Alexey Knyazev 13. января 2010 21:32

Веб-служба, веб-сервис (англ. web service) — программная система, идентифицируемая строкой URI, чьи общедоступные интерфейсы определены на языке XML. Описание этой программной системы может быть найдено другими программными системами, которые могут взаимодействовать с ней согласно этому описанию посредством сообщений, основанных на XML, и передаваемых с помощью интернет-протоколов. Веб-служба является единицей модульности при использовании сервисно-ориентированной архитектуры приложения.

Для демонстрации работы с Web-службами из SQL Server`a, я воспользовался открытым Web-сервисом Центрального банка Российской Федерации, этот сервис привлекателен тем, что информация всегда актуальна, т.к. обновляется с завидной регулярностью и может быть полезна в реальных проектах.

Адрес Веб-сервиса: http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL.

 

Веб сервис для получения ежедневных данных:

  • Сальдо операций ЦБ РФ по предоставлению/абсорбированию ликвидности
  • Получение новостей сервера
  • Операции на открытом рынке
  • Операции Банка России на рынке государственных ценных бумаг по поручению Министерства финансов Российской Федерации
  • Получение основной информации
  • Ставка рефинансирования, золотовалютные резервы, денежная база, денежная масса
  • Валютный своп buy/sell overnight
  • Динамики ставок привлечения средств по депозитным операциям
  • Динамика учетных цен драгоценных металлов и т.д.

Согласитесь, что достаточно ценная информация, а особенно ценна она своей актуальностью. Результат возвращается, как в виде DataSet, так и XMLDocument, но начнём по порядку...

Для начала продемонстрирую на небольшом примере, как работать с этим Web-сервисом из Windows-приложения. Запускаем Microsoft Visual Studio 2008 (но пример прекрасно работает и с 2005ой версией) и создадим Windows Forms Application

.

На форму добавим всего два компонента DataGridView (назовём его dg) и Button (назовём btn). Всё, что будет делать наше приложение - это по кнопке выводить результат(DataSet) в нашу табличку. Теперь необходимо подключить нашу Веб службу к проекту, для этого в Solution Explorer`e правой кнопкой мыши по References и Add Service Reference...

В поле Address добавляем адресс нашей Веб службы(http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL), а в поле Namespace имя, под которым у нас в проекте будет фигурировать служба (WS)

 

 Далее всё более, чем тривиально, перед нами весь набор возможностей данной Веб службы

В данном примере я прочитаю все новости за последние 5 дней, для этого на кнопку вешаю код:

WS.DailyInfoSoap i = new WS.DailyInfoSoapClient();
dg.DataSource = i.NewsInfo(DateTime.Now.AddDays(-5), DateTime.Now).Tables[0].DefaultView;

 

 

Результат вывожу в виде таблицы:

 

Как сами видите нет ничего сложного, далее можно оперативно получить информацию по всем операциям ЦБРФ. Но согласитесь гораздо удобнее считывать информацию фоново, например по расписанию, и сохранять информацию в БД. Для этого мы создадим сборку CLR (Common Language Runtime)

Но...сперва все подводные камни, с которыми и сам столкнулся. Подготовим наш сервер БД, для того, чтобы можно было подключать сборки:

SP_CONFIGURE 'clr enabled', 1
GO
RECONFIGURE
GO

Создадим тестовую БД и выставим Свойство базы данных TRUSTWORTHY:

CREATE DATABASE TestDB
GO
ALTER DATABASE TestDB SET TRUSTWORTHY ON
GO

Затем на подобии с вариантом для Windows-приложения напишем код для нашей сборки и скомпилируем dll-ку:

using System;
using Microsoft.SqlServer.Server;
using System.Data;
using System.Data.SqlTypes;
using System.Collections;
using CLRWS.WS;

public class WSClass
{
    [SqlFunction(SystemDataAccess = SystemDataAccessKind.Read,
FillRowMethodName = "GetListInfo")]

    public static IEnumerable GetNews(DateTime From)
    {
        CLRWS.WS.DailyInfoSoap i = new CLRWS.WS.DailyInfoSoapClient();
        DataTable t = new DataTable();
        t = i.NewsInfo(From, DateTime.Now).Tables[0];
        return t.Rows;
    }

    public static void GetListInfo(
                    object obj,
                    out SqlInt32 Doc_id,
                    out SqlDateTime DocDate,
                    out SqlString Title,
                    out SqlString Url)
    {
        DataRow r = (DataRow)obj;
        Doc_id = new SqlInt32(Convert.ToInt32(r["Doc_id"].ToString()));
        DocDate = new SqlDateTime(Convert.ToDateTime(r["DocDate"].ToString()));
        Title = new SqlString(r["Title"].ToString());
        Url = new SqlString(r["Url"].ToString());
    }

}

Код компилируется без проблем, и теперь попытаемся подключить нашу сборку, предварительно перенесём её в отдельную папку C:\MyCLR:

CREATE ASSEMBLY ClrWebServices
FROM 'C:\MyCLR\CLRWS.dll'
WITH PERMISSION_SET = UNSAFE;
GO

Но тут же получаем ошибку:

Msg 10301, Level 16, State 1, Line 1 Assembly ‘CLRWS’ references assembly ’system.servicemodel, version=3.0.0.0, culture=neutral, publickeytoken=b77a5c561934e089.’, which is not present in the current database. SQL Server attempted to locate and automatically load the referenced assembly from the same location where referring assembly came from, but that operation has failed (reason: 2(failed to retrieve text for this error. Reason: 1815)). Please load the referenced assembly into the current database and retry your request.

Для нашей сборки не хватает ряда библиотек и начиная с system.servicemodel, расположенной в папке C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0, начинаем копировать библиотеки в папку C:\MyCLR. Кромя того, ряд библиотек придётся взять из папки C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727, общее кол-во библиотек можно увидеть ниже:

И теперь вуаля...скрипт отрабатывает без ошибок, создадим функцию для работы с нашей сборкой:

CREATE FUNCTION [dbo].[GetNews]
(
@From datetime
)
RETURNS TABLE
(
Doc_id INT,
DocDate DATETIME,
Title NVARCHAR(max),
Url NVARCHAR(max)
)
AS
EXTERNAL NAME [ClrWebServices].[WSClass].[GetNews]
GO

Ну и пробуем запустить эту функцию, в качестве входного параметра указывается дата, с которой мы берём новости и по сегодняшний день:

SELECT * from [dbo].[GetNews] ('20090101')

Но тут же получаем ошибку:

Msg 6522, Level 16, State 1, Line 1 A .NET Framework error occurred during execution of user-defined routine or aggregate “GetNews”: System.InvalidOperationException: Could not find default endpoint element that references contract ‘WS.DailyInfoSoap’ in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element. System.InvalidOperationException: at System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName) at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName) at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address) at System.ServiceModel.ChannelFactory`1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress) at System.ServiceModel.EndpointTrait`1.CreateSimplexFactory() at System.ServiceModel.EndpointTrait`1.CreateChannelFactory() at System.ServiceModel.ClientBase`1.CreateChannelFactoryRef(EndpointTrait`1 endpointTrait) at System.ServiceModel.ClientBase`1.InitializeChannelFactoryRef() at System.ServiceModel.ClientBase`1..ctor() at CLRWS.WS.DailyInfoSoapClient..ctor() at WSClass.GetNews(DateTime From)

Всё дело в том, что нам нужна информация, которая находится в файле app.config:

 а именно

Для этого изменяем немного нашу сборку, компилируем и пересоздаём её и нашу функцию, вот так выглядит новая версия:

using System;
using Microsoft.SqlServer.Server;
using System.Data;
using System.Data.SqlTypes;
using System.Collections;
using CLRWS.WS;
using System.ServiceModel;

public class WSClass
{
    [SqlFunction(SystemDataAccess = SystemDataAccessKind.Read,
FillRowMethodName = "GetListInfo")]

    public static IEnumerable GetNews(DateTime From)
    {
        EndpointAddress ea = new EndpointAddress("http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL");
        BasicHttpBinding bin = new BasicHttpBinding();

        CLRWS.WS.DailyInfoSoap i = new CLRWS.WS.DailyInfoSoapClient(bin, ea);
        DataTable t = new DataTable();
        t = i.NewsInfo(From, DateTime.Now).Tables[0];
        return t.Rows;
    }

    public static void GetListInfo(
                    object obj,
                    out SqlInt32 Doc_id,
                    out SqlDateTime DocDate,
                    out SqlString Title,
                    out SqlString Url)
    {
        DataRow r = (DataRow)obj;
        Doc_id = new SqlInt32(Convert.ToInt32(r["Doc_id"].ToString()));
        DocDate = new SqlDateTime(Convert.ToDateTime(r["DocDate"].ToString()));
        Title = new SqlString(r["Title"].ToString());
        Url = new SqlString(r["Url"].ToString());
    }

}

После запуска нашей функции с уже новой сборкой

SELECT * from [dbo].[GetNews] ('20090101')

получаем новую ошибку

Msg 6522, Level 16, State 1, Line 1 A .NET Framework error occurred during execution of user-defined routine or aggregate “GetNews”: System.Configuration.ConfigurationErrorsException: The type ‘Microsoft.VisualStudio.Diagnostics.ServiceModelSink.Behavior, Microsoft.VisualStudio.Diagnostics.ServiceModelSink, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ registered for extension ‘Microsoft.VisualStudio.Diagnostics.ServiceModelSink.Behavior’ could not be loaded. (c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Config\machine.config line 189) System.Configuration.ConfigurationErrorsException: at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult) at System.Configuration.BaseConfigurationRecord.Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult, Boolean getLkg, Boolean getRuntimeObject, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject) at System.Configuration.BaseConfigurationRecord.GetSection(String configKey, Boolean getLkg, Boolean checkPermission) at System.C…

Ну эту ошибку легко убрать, достаточно отключить дебагинг: [Program Files]\Microsoft Visual Studio 9.0\Common7\IDE\vsdiag_regwcf.exe -u

но и после этого ошибка, но уже новая:

Msg 6522, Level 16, State 1, Line 1 A .NET Framework error occurred during execution of user-defined routine or aggregate “GetNews”: System.ServiceModel.CommunicationException: There was an error in serializing body of message : ‘Cannot load dynamically generated serialization assembly. In some hosting environments assembly load functionality is restricted, consider using pre-generated serializer. Please see inner exception for more information.’. Please see InnerException for more details. —> System.InvalidOperationException: Cannot load dynamically generated serialization assembly. In some hosting environments assembly load functionality is restricted, consider using pre-generated serializer. Please see inner exception for more information. —> System.IO.FileLoadException: LoadFrom(), LoadFile(), Load(byte[]) and LoadModule() have been disabled by the host. System.ServiceModel.CommunicationException: Server stack trace: at System.ServiceModel.Dispatcher.XmlSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest) at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest) at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer) at System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer) at System.ServiceModel.Channels.BodyWriterMessage.OnWriteBodyContents(XmlDictionaryWriter writer) at System.ServiceModel.Channels.Message.OnWriteMessage(XmlDictionaryWriter writer) at System.ServiceModel.Channels.Message.WriteMessage(XmlDictionaryWriter writer) at System.ServiceModel.Channels.BufferedMessageWriter.WriteMessage(Message message, BufferManager bufferManager, Int32 initialOffset, Int32 maxSizeQuota) at…

Сериализация XML из объектов базы данных CLR, кромя того о подобной ошибке можно прочитать в базе знаний Майкрософт http://support.microsoft.com/kb/913668.

После всех "заморочек", продемонстрирую, как же всё-таки подключить сборку для работы с Веб-сервисами. Для начала удалим нашу БД TestDB, т.к. всё, что было сделано до этого было лишним. Ну и создадим её заново. Для создания "правильной" сборки нам потребуются несколько утилит:

1) Web Services Description Language Tool (Wsdl.exe) для создания прокси-сборки (C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\wsdl.exe)

2) csc.exe для компилирования прокси-сборки (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CSC.exe)

3) XML Serializer Generator Tool (Sgen.exe) - Создает сборку сериализации XML для типов в указанной сборке (C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sgen.exe)

Теперь создаём прокси-сбоку:

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\wsdl.exe" /o:CBRF.cs /n:WS http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL

на выходе получаем нашу сборку CBRF.cs

Теперь если немного изучить её, то наш финальный вариант CLR-сборки выглядит так:

using System;
using Microsoft.SqlServer.Server;
using System.Data;
using System.Data.SqlTypes;
using System.Collections;
using WS;

public class WSClass
{
            [SqlFunction(SystemDataAccess = SystemDataAccessKind.Read,
		FillRowMethodName = "GetListInfo")]

    public static IEnumerable GetNews(DateTime From)
    {
	WS.DailyInfo i=new WS.DailyInfo();
	DataTable t = new DataTable();
	t=i.NewsInfo(From, DateTime.Now).Tables[0];
        return t.Rows;
    }

        public static void GetListInfo(
                        object obj,
                        out SqlInt32 Doc_id,
                        out SqlDateTime DocDate,
                        out SqlString Title,
                        out SqlString Url)
        {
            DataRow r = (DataRow)obj;
            Doc_id = new SqlInt32(Convert.ToInt32(r["Doc_id"].ToString()));
            DocDate = new SqlDateTime(Convert.ToDateTime(r["DocDate"].ToString()));
            Title = new SqlString(r["Title"].ToString());
            Url = new SqlString(r["Url"].ToString());
        }

}

Сохраним этот код в отдельный файл, например MyCLR.cs

Теперь поместим в одну папку два наших файла: CBRF.cs и MyCLR.cs и скомпилируем их в одну dll-ку, для этого из директории с этими файлами запустим

"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CSC" /target:library /out:WS.dll *.cs

После запуска появится наша библиотека WS.dll

Последним шагом создадим сборку сериализации

"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\sgen.exe" /a:WS.dll

на выходе ещё одна библиотека WS.XmlSerializers.dll

ВСЁ!!! Теперь подключим наши библиотеки:

CREATE ASSEMBLY ClrWebServices
FROM 'C:\MyCLR\WS.dll'
WITH PERMISSION_SET = UNSAFE;
GO

CREATE ASSEMBLY [ClrWebServices.XmlSerializers]
FROM 'C:\MyCLR\WS.XmlSerializers.dll'
WITH PERMISSION_SET = SAFE;
GO

Создадим функцию:

CREATE FUNCTION [dbo].[GetNews]
(
@From datetime
)
RETURNS TABLE
(
Doc_id INT,
DocDate DATETIME,
Title NVARCHAR(max),
Url NVARCHAR(max)
)
AS
EXTERNAL NAME [ClrWebServices].[WSClass].[GetNews]
GO

Ну и получим результат:

SELECT * from [dbo].[GetNews] ('20090101')

 

 

Ниже эти две библиотеки в архиве:

WS.rar

Tags: , , , , , ,

SQL Server

Чтение почты (POP3) в SQL Server 2005/2008

by Alexey Knyazev 16. декабря 2009 21:08

Продолжаю тему безполезных примеров CLR-сборок в помощь администратору(разработчику) БД.

В этот раз решил читать почту в SQL Server 2005/2008/2008R2 через протокол POP3. Многие скажут, что сервер БД не предназначен для этого, но ВДРУГ!?

Конечно для этого у нас есть SQL Mail, но учитывая ряд ограничений, о которых чуть ниже, пришлось посмотреть в сторону собственной сборки. Для чтения почты используются, как правило, протокол POP3 либо IMAP(о нём в следующий раз, возможно так же в качестве очередной CLR-сборки).

Ну и для начала всё-таки об ограничениях SQL Mail:

В будущей версии Microsoft SQL Server эта возможность будет удалена. Избегайте использования этой возможности в новых разработках и запланируйте изменение существующих приложений, в которых она применяется. Чтобы отправить почту из SQL Server, используйте компонент Database Mail.

...но как читать-то почту!? Ведь Database Mail только отправляет почту через SMTP-протокол...

Служба SQL Mail требует наличия подключения к почтовой станции, почтовый ящик, почтовый профиль и учетную запись пользователя домена Microsoft, используемую для входа на SQL Server (учетная запись пользователя должна быть в том же домене, что и SQL Server). Служба MSSQLServer должна быть запущена под этой учетной записью домена пользователя. С помощью расширенных хранимых процедур службы SQL Mail можно отправлять сообщения из триггера или хранимой процедуры. Хранимые процедуры службы SQL Mail могут обрабатывать запросы, полученные по электронной почте, и возвращать результирующий набор, создавая ответное электронное сообщение.

Эти ограничения заставили взглянуть в сторону изучения протоколов POP3/IMAP.

Разбирём POP3 чуть подробнее:

Краткое, но достаточно емкое описание почтового протокола POP3.

Перед работой через протокол POP3 сервер прослушивает порт 110. Когда клиент хочет использовать этот протокол, он должен создать TCP соединение с сервером. Когда соединение установлено, сервер отправляет приглашение. Затем клиент и POP3 сервер обмениваются информацией пока соединение не будет закрыто или прервано.

Команды POP3 состоят из ключевых слов, за некоторыми следует один или более аргументов. Все команды заканчиваются парой CRLF (в Visual Basic константа vbCrLf). Ключевые слова и аргументы состоят из печатаемых ASCII символов. Ключевое слово и аргументы разделены одиночным пробелом. Ключевое слово состоит от 3-х до 4-х символов, а аргумент может быть длиной до 40-ка символов.

Ответы в POP3 состоят из индикатора состояния и ключевого слова, за которым может следовать дополнительная информация. Ответ заканчивается парой CRLF. Существует только два индикатора состояния: "+OK" - положительный и "-ERR" - отрицательный.

Ответы на некоторые команды могут состоять из нескольких строк. В этих случаях каждая строка разделена парой CRLF, а конец ответа заканчивается ASCII символом 46 (".") и парой CRLF.

POP3 сессия состоит из нескольких режимов. Как только соединение с сервером было установлено и сервер отправил приглашение, то сессия переходит в режим авторизации. В этом режиме клиент должен идентифицировать себя на сервере. После успешной идентификации сессия переходит в режим транзакции. В этом режиме клиент запрашивает сервер выполнить определённые команды. Когда клиент отправляет команду QUIT, сессия переходит в режим обновления. В этом режиме POP3 сервер освобождает все занятые ресурсы и завершает работу. После этого TCP соединение закрывается.

Список команд:

  • USER - Когда РОРЗ -сессия находится в состоянии аутентификации (AUTHORIZATION), и клиент должен зарегистрировать себя на РОРЗ -сервере. Это может быть выполнено либо с помощью команд USER и PASS — ввод открытых пользовательского идентификатора и пароля (именно этот способ используется чаще), либо командой АРОР — аутентификация цифровой подписью, на базе секретного ключа. Любой РОРЗ -сервер должен поддерживать хотя бы один из механизмов аутентификации. Аргументом — "name" является строка, идентифицирующая почтовый ящик системы. Этот идентификатор должен быть уникальным в данной почтовой системе РОРЗ -сервера. Если ответом на эту команду является строка индикатора "+OK", клиент может отправлять команду PASS — ввод пароля или QUIT — завершить сессию. Если ответом является строка "-ERR", клиент может либо повторить команду USER, либо закрыть сессию
  • PASS - Аргументом команды является строка пароля данного почтового ящика. После получения команды PASS, РОРЗ -сервер, на основании аргументов команд USER и PASS, определяет возможность доступа к заданному почтовому ящику. Если РОРЗ -сервер ответил "+OK", это означает, что аутентификация клиента прошла успешно и он может работать со своим почтовым ящиком, т. е. сессия переходит в состояние TRANSACTION. Если РОРЗ- сервер ответил "-ERR", то либо был введен неверный пароль, либо не найден указанный почтовый ящик
  • STAT - После того как клиент успешно прошел процедуру аутентификации в РОРЗ- сервере, и РОРЗ- сервер "закрыл" определенный почтовый ящик только для использования данным клиентом (для тех, кто работал с базами данных, это называется EXCLUSIVE ACCESS LOCK), РОРЗ- сессия переходит в режим TRANSACTION, и клиент может начать работу со своей почтой Команда STAT (без аргументов) используется для просмотра состояния текущего почтового ящика. В ответ РОРЗ- сервер возвращает строку, содержащую количество и общий размер в байтах сообщений, которые клиент может получить с РОРЗ- сервера. Сообщения, помеченные на удаление, не учитываются
  • LIST [msg] - Команда LIST может передаваться как с аргументом msg — номером сообщения, так и без аргумента. Если команда содержит аргумент, и сообщение с указанным номером существует, ответом на нее будет "информационная строка", которая содержит номер сообщения и размер сообщения в байтах. Если аргумент не указан — ответом будет список информационных строк обо всех сообщениях в данном почтовом ящике. Сообщения, помеченные на удаление не фигурируют в этом списке
  • RETR msg - Используется для передачи клиенту запрашиваемого сообщения. Аргумент команды — номер сообщения. Если запрашиваемого сообщения нет, возвращается отрицательный индикатор "-ERR".
  • DELE msg - Аргумент команды— номер сообщения. Сообщения, помеченные на удаление, реально удаляются только после закрытия транзакции при отправке команды QUIT.
  • NOOP - Для проверки состояния соединения с РОРЗ- сервером используется команда NOOP. При активном соединении ответом на нее будет положительный индикатор "+ОК":
  • RSET - Для отката транзакции внутри сессии используется команда RSET (без аргументов). Если пользователь случайно пометил на удаление какие-либо сообщения, он может убрать эти пометки, отправив эту команду:
  • TOP msg n - По этой команде пользователь может получить "n" первых строк сообщения с номером "msg". РОРЗ- сервер по запросу клиента отправляет заголовок сообщения, затем пустую строку, затем требуемое количество строк сообщения (если количество строк в сообщении меньше указанного в параметре "n", пользователю передается все сообщение).
  • QUIT - К командам состояния AUTHORIZATION может относиться команда закрытия РОРЗ- сессии — QUIT, если она была отправлена в режиме AUTHORIZATION (например, при вводе неправильного пароля или идентификатора пользователя): Эта команда отправляется без аргументов и всегда имеет единственный ответ "+ОК".

Как видно из описания список команд не велик. В сборку я включил всего 3 команды: LIST(список писем), RETR(чтение письма), DELE(удаление письма). Все другие команды игнорируются, но вы можете сами дополнить мой пример, для этого и выкладываю исходный код сборки:

using System;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Net.Sockets;
using System.Text;

public class POP3CLR
{
    [SqlFunction(FillRowMethodName = "FillRow"
        , TableDefinition = "SERVER: nvarchar(max)")
    ]

    public static IEnumerable POP3Command(string POP3Server, string Port, string User, string Pass, string Command)
    {

        ArrayList rows = new ArrayList();
        if (Command.Length > 3)
        {
            if (Command != "LIST" && Command.Substring(0, 4) != "RETR" && Command.Substring(0, 4) != "DELE")
            {
                Command = "HELP";
            }
        }
        else
        {
            Command = "HELP";
        }

        if (Command == "HELP")
        {

            rows.Add(new object[] {"LIST-список информационных "+
                                   "строк обо всех сообщениях в данном почтовом ящике. "+
                                   "Сообщения, помеченные на удаление не фигурируют в этом списке." });
            rows.Add(new object[] {"RETR msg-Используется для передачи клиенту запрашиваемого сообщения. "+
                                   "Аргумент команды — номер сообщения. Если запрашиваемого сообщения нет, "+
                                   "возвращается отрицательный индикатор '-ERR'." });
            rows.Add(new object[] {"DELE msg-Аргумент команды— номер сообщения. "+
                                   "Сообщения, помеченные на удаление, реально удаляются только "+
                                   "после закрытия транзакции при отправке команды QUIT." });
            return rows;
        }

        TcpClient tcpClient = new TcpClient();
        tcpClient.Connect(POP3Server, Convert.ToInt32(Port));
        NetworkStream netStream = tcpClient.GetStream();
        System.IO.StreamReader strReader = new System.IO.StreamReader(netStream);

        if (tcpClient.Connected)
        {

            byte[] WriteBuffer = new byte[1024];
            ASCIIEncoding enc = new System.Text.ASCIIEncoding();
            WriteBuffer = enc.GetBytes("USER " + User + "\r\n");
            netStream.Write(WriteBuffer, 0, WriteBuffer.Length);
            rows.Add(new object[] { strReader.ReadLine() + "\r\n\r\n" });
            WriteBuffer = enc.GetBytes("PASS " + Pass + "\r\n");
            netStream.Write(WriteBuffer, 0, WriteBuffer.Length);
            rows.Add(new object[] { strReader.ReadLine() + "\r\n\r\n" });
            WriteBuffer = enc.GetBytes(Command + "\r\n");
            netStream.Write(WriteBuffer, 0, WriteBuffer.Length);
            if (Command.Substring(0, 4) == "DELE")
            {
                rows.Add(new object[] { strReader.ReadLine() + "\r\n\r\n" });
            }
            else
            {
                string ListMessage;
                while (true)
                {
                    ListMessage = strReader.ReadLine();
                    if (ListMessage == ".")
                    {
                        break;
                    }
                    else
                    {
                        rows.Add(new object[] { ListMessage + "\r\n\r\n" });
                        continue;
                    }
                }
            }
            WriteBuffer = enc.GetBytes("QUIT\r\n");
            netStream.Write(WriteBuffer, 0, WriteBuffer.Length);
            rows.Add(new object[] { strReader.ReadLine() + "\r\n\r\n" });
        }
        return rows;
    }

    public static void FillRow(Object row, out string Server)
    {

        object[] xrow = (object[])row;
        Server = (string)xrow[0];

    }

}

Регистрируем сборку и создаём на её основе функцию:

CREATE ASSEMBLY AssemblyPOP3
FROM 'C:\CLR\POP3CLR.dll'
WITH PERMISSION_SET = UNSAFE
GO

--Создаём функцию
CREATE FUNCTION POP3Command
(
@POP3Server nvarchar(128),
@Port nvarchar(5),
@User nvarchar(128),
@Pass nvarchar(128),
@Command nvarchar(50)
)
RETURNS TABLE
(
[SERVER:] NVARCHAR(max)
)
EXTERNAL NAME AssemblyPOP3.POP3CLR.POP3Command;

Ну и пример работы с этой функцией:

SELECT * FROM POP3Command(
'pop3.MyServer.ru', 110, 'E-Mail@MyServer.ru', 'MyPassword', 'LIST'
)

Если у вас возникнут вопросы, то я буду рад помочь, пишите…

Tags: , , , ,

SQL Server

Powered by BlogEngine.NET 1.6.0.0
Все права защищены © T-SQL.RU | Alexey Knyazev 2008-2010

MVP:SQL