Получение сообщений SQL Server с помощью ADO и win32com

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

Для этого я надеюсь использовать интересное сочетание ADO, win32com и adodbapi. В настоящее время я могу легко подключиться к серверу и выполнить команду BACKUP DATABASE T-SQL.

Это работает, однако выполнение команды часто занимает много времени (особенно в очень больших базах данных). С этой целью я надеялся захватить и проанализировать событие InfoMessage (MSDN) и используйте его для отображения процентной шкалы/счетчика.

Это мне тоже удалось, теперь я застрял на последнем препятствии, разбирая событие. Документы MSDN говорят, что я должен быть передано либо Error, либо < объект href="http://msdn.microsoft.com/en-us/library/ms675299(v=vs.85).aspx" rel="nofollow noreferrer">Errors в параметре pError. Однако win32com передает мне объект PyIUnknown, с которым я не знаю, что делать.

Ниже приведен код, который я написал до сих пор:

import win32com
import pythoncom
import adodbapi
from win32com.client import gencache
gencache.EnsureModule('{2A75196C-D9EB-4129-B803-931327F72D5C}', 0, 2, 8)

defaultNamedOptArg=pythoncom.Empty
defaultNamedNotOptArg=pythoncom.Empty
defaultUnnamedArg=pythoncom.Empty

class events():
    def OnInfoMessage(self, pError, adStatus, pConnection):
        print 'A', pError
        #print 'B', adStatus
        #print 'C', pConnection

# This is taken from the makepy file
#    def OnCommitTransComplete(self, pError=defaultNamedNotOptArg, adStatus=defaultNamedNotOptArg, pConnection=defaultNamedNotOptArg): pass
    def OnWillExecute(self, Source=defaultNamedNotOptArg, CursorType=defaultNamedNotOptArg, LockType=defaultNamedNotOptArg, Options=defaultNamedNotOptArg
            , adStatus=defaultNamedNotOptArg, pCommand=defaultNamedNotOptArg, pRecordset=defaultNamedNotOptArg, pConnection=defaultNamedNotOptArg):
        return Source
#    def OnDisconnect(self, adStatus=defaultNamedNotOptArg, pConnection=defaultNamedNotOptArg): pass
    def OnExecuteComplete(self, RecordsAffected=defaultNamedNotOptArg, pError=defaultNamedNotOptArg, adStatus=defaultNamedNotOptArg, pCommand=defaultNamedNotOptArg
            , pRecordset=defaultNamedNotOptArg, pConnection=defaultNamedNotOptArg): pass
        #print pError
    def OnWillConnect(self, ConnectionString=defaultNamedNotOptArg, UserID=defaultNamedNotOptArg, Password=defaultNamedNotOptArg, Options=defaultNamedNotOptArg
            , adStatus=defaultNamedNotOptArg, pConnection=defaultNamedNotOptArg): pass
#    def OnConnectComplete(self, pError=defaultNamedNotOptArg, adStatus=defaultNamedNotOptArg, pConnection=defaultNamedNotOptArg): pass
#    def OnBeginTransComplete(self, TransactionLevel=defaultNamedNotOptArg, pError=defaultNamedNotOptArg, adStatus=defaultNamedNotOptArg, pConnection=defaultNamedNotOptArg):pass
#    def OnRollbackTransComplete(self, pError=defaultNamedNotOptArg, adStatus=defaultNamedNotOptArg, pConnection=defaultNamedNotOptArg): pass




if __name__ == '__main__':

    pythoncom.CoInitialize()
    conn = win32com.client.DispatchWithEvents("ADODB.Connection", events)
    print dir(conn)
    conn.ConnectionString = 'Initial Catalog=test; Data Source=HPDX2250RAAZ\\SQLEXPRESS; Provider=SQLOLEDB.1; Integrated Security=SSPI'
    conn.CommandTimeout = 30
    print conn.ConnectionString
    conn.Open()

    con = adodbapi.Connection(conn)

    c = con.cursor()
    import time
    print 'Execute'
    time.sleep(1)
    c.execute(u"BACKUP DATABASE [test] TO DISK = N'c:/test/test2' WITH STATS = 1")
    print 'Done Execute'

Кто-нибудь может извлечь информационные сообщения из событий?

Это реализовано в VB (я думаю)

В качестве примера одного из этих сообщений запустите SQL Server Management Studio и запустите резервное копирование с помощью сценария (вы можете создать сценарий, используя диалоговое окно резервного копирования и кнопку сценария в левом верхнем углу). Вы заметите, что когда вы запускаете сценарий, окно сообщений будет заполняться процентными сообщениями. Это то, что я хочу.

Редактировать:

Ниже приведен новый код, который я использую для опроса COM-объектов, которые передаются в InfoMessage. Это основано на ответе ниже, я помещаю его здесь на случай, если кому-то еще это понадобится.

def OnInfoMessage(self, pError, adStatus, pConnection):
    print 'Info Message'
    a = pError.QueryInterface(pythoncom.IID_IDispatch)
    a = win32com.client.Dispatch(a)
    print a.Description
    print a.Number
    print a.Source
    #print 'B', adStatus
    c = pConnection.QueryInterface(pythoncom.IID_IDispatch)
    c = win32com.client.Dispatch(c)
    print c.Errors.Count
    print c.Errors.Item(0).Description
    print c.Errors.Clear()
    print 'c', adStatus

person thomas    schedule 03.05.2011    source источник


Ответы (1)


Читая MSDN, кажется, что только Error объекты должны передаваться обработчикам событий. Если ошибок несколько, их можно получить из Errors коллекции вашего Connection объекта. Таким образом, вы должны ожидать, что только объекты Error будут переданы в InfoMessage(). Если вместо этого вы получите PyIUnknown, возможно, вы можете попробовать вызвать на нем QueryInterface() и запросить IDispatch? Вы также можете попробовать запросить конкретный пользовательский интерфейс, который использует Error, но я не помню, поддерживает ли Pythoncom настраиваемые интерфейсы (т. проверьте это сами. В любом случае, IDispatch должен работать несмотря ни на что, поскольку именно его использует VB6.

person Boaz Yaniv    schedule 03.05.2011
comment
Запрашивая интерфейс IDispatch, а затем передавая его в win32com.client.Dispatch(), мы получаем объект COM с поздней привязкой, который позволяет мне получить доступ к нужным мне данным. Однако я получаю только один вызов InfoMessage с объектом Error. - person thomas; 04.05.2011
comment
Как сказано в документации, если ошибок больше одной, вы можете получить все ошибки из Connection.Errors. Я не уверен, как это поможет вам отслеживать прогресс. - person Boaz Yaniv; 04.05.2011
comment
Я посмотрел, что и объект Connection, который попадает в InfoMessage, и исходный объект после того, как я сделал этот вызов. Оба объекта содержат только один Error, и именно он был передан InfoMessage в параметре pError. - person thomas; 04.05.2011
comment
Для каждого сообщения о проценте выполнения должно быть Error. С STAT = 10 должно быть ~10 Errors плюс некоторые другие сообщения, которые отправляет команда BACKUP. - person thomas; 04.05.2011