使用 ADO 和 win32com 获取 SQL Server 消息
我目前正在尝试编写一个工具,使不懂计算机的用户可以轻松备份 SQL Server 数据库。
为此,我希望使用 ADO、win32com 和 adodbapi 的有趣组合。目前,我可以轻松连接到服务器并发出 BACKUP DATABASE T-SQL 命令。
这是可行的,但是命令的执行通常需要很长时间(尤其是在非常大的数据库上)。为此,我希望捕获并解析 InfoMessage
事件 (MSDN)并用它来显示百分比栏/计数器。
我也做到了这一点,现在我陷入了最后的障碍,解析事件。 MSDN 文档说我应该传递 错误 或 < pError 中的 href="http://msdn.microsoft.com/en-us/library/ms675299(v=vs.85).aspx" rel="nofollow noreferrer">Errors 对象
参数。但是 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 并使用脚本运行备份(您可以使用备份对话框和左上角的脚本按钮生成脚本)。您会注意到,运行脚本时,消息框将填充完成消息的百分比。这些就是我想要的。
编辑:
下面是我用来询问传递给 InfoMessage
的 COM 对象的新代码。这是基于下面的答案,我将其放在这里以防其他人需要它。
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
I am currently trying to write a tool that will make it very easy for a non-computer literate user to backup a SQL Server database.
To do this I am hoping to use an interesting mix of ADO, win32com and adodbapi. Currently I can easily connect to the server and issues a BACKUP DATABASE
T-SQL command.
This works, however it often takes a long time for the command to execute (especially on very large databases). To this end I was hoping to capture and parse the InfoMessage
event (MSDN) and use it to show a percentage bar/counter.
This I have also managed, I now I'm stuck at the final hurdle, parsing the event. The MSDN docs say that I should be passed either an Error or Errors object in the pError
parameter. However win32com passes me a PyIUnknown
object which I don't know how to deal with.
Below is the code that I have written so far:
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'
Can anyone extract the Informational messages from the events?
This is it implemented in VB (I think)
For an example of one of these messages start up SQL Server Management Studio and run a backup using a script (you can generate the script using the backup dialogue and the script button in the top left). You will notice that when you run the script the messages box will populate with percentage complete messages. These are what I want.
Edit:
Below is the new code that I'm using to interrogate the COM objects that get passed to the InfoMessage
. This is based on the answer below, I'm putting it here in case anyone else needs it.
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
阅读 MSDN,似乎只有
Error
对象应该传递给事件处理程序。如果存在多个错误,您可以从Connection
对象的Errors
集合中获取它们。因此,您应该只期望将 Error 对象传递给InfoMessage()
。如果您得到 PyIUnknown,也许您可以尝试在其上调用 QueryInterface() 并请求 IDispatch?您还可以尝试请求Error
使用的特定自定义接口,但我不记得 Pythoncom 是否支持自定义(即非 IDispatch)接口,而且我的互联网现在正在爬行,所以我无法检查所以你必须自己检查一下。无论如何,IDispatch 无论如何都应该工作,因为这就是 VB6 使用的。Reading MSDN, it seems only
Error
objects should get passed to the event handlers. If there are multiple errors, you can get them from theErrors
collection of yourConnection
object. So you should only expect Error objects to get passed toInfoMessage()
. If you get PyIUnknown instead, maybe you can try to callQueryInterface()
on it and request IDispatch? You can also try to request the specific custom interfaceError
uses, but I don't remember if Pythoncom supports custom (i.e. non-IDispatch) interfaces, and my internet is crawling right now so I can't check so you'll have to check that yourself. Anyway, IDispatch should work no matter what, since that's what VB6 uses.