在sql server 7.0和sql server 6.5中提供了7個(gè)擴(kuò)展的存儲(chǔ)過(guò)程,可以通過(guò)自己開(kāi)發(fā)的或office等現(xiàn)成的com對(duì)象擴(kuò)展sql server的功能。sql server還提供了一種錯(cuò)誤處理機(jī)制,可以把出錯(cuò)信息寫(xiě)到sql代理日志中。利用com自動(dòng)化操作服務(wù),還可以把sql server與微軟的exchange server、index server和其他可以通過(guò)com自動(dòng)化操作服務(wù)控制其他軟件進(jìn)行集sql server 6.5引進(jìn)了對(duì)象自動(dòng)操作環(huán)境,它最初被稱作ole。隨著時(shí)間的變遷對(duì)象操作的名稱也有所變化,然而與sql server 6.5相比,sql server 7.0中的自動(dòng)操作環(huán)境沒(méi)有改變,因此微軟的文檔中仍然把這一功能稱作ole操作而不是com操作,在查閱sql server在線手冊(cè)(bol)時(shí)尤其需要注意這一點(diǎn)。下面我們來(lái)討論如何使用sql server的com自動(dòng)操作存儲(chǔ)過(guò)程以及com自動(dòng)操作如何幫助我們解決現(xiàn)實(shí)的編程問(wèn)題。
com操作的細(xì)節(jié)
表1列出了sql server中的7個(gè)用于com操作的擴(kuò)展存儲(chǔ)過(guò)程。當(dāng)自動(dòng)操作一個(gè)com對(duì)象時(shí),需要首先通過(guò)調(diào)用sp_oacreate建立一個(gè)com對(duì)象的實(shí)例,然后通過(guò)一系列的sp_oagetproperty、sp_oasetproperty和sp_oamethod調(diào)用完成需要完成的任務(wù),在完成對(duì)com對(duì)象的操作后,還需要調(diào)用sp_oadestroy釋放該對(duì)象。在詳細(xì)地研究每個(gè)儲(chǔ)存過(guò)程時(shí),請(qǐng)注意二個(gè)很重要的問(wèn)題。
第一,必須提供調(diào)用的所有參數(shù),因?yàn)樽詣?dòng)操作功能不支持有名參數(shù),如果不能使用一個(gè)詳細(xì)的參數(shù),需要向它傳遞一個(gè)null作為占位符;第二,每個(gè)調(diào)用返回一個(gè)整數(shù)類型的hresult,如果調(diào)用成功則該值為0。在后面,我們將討論如何處理返回值為非。
  存儲(chǔ)過(guò)程 描述 
  sp_oacreate 建立自動(dòng)操作對(duì)象的一個(gè)實(shí)例 
  sp_oadestroy 釋放一個(gè)對(duì)象的實(shí)例 
  sp_oageterrorinfo 從其他過(guò)程返回的hresult中獲得錯(cuò)誤描述信息 
  sp_oagetproperty 把一個(gè)對(duì)象的屬性存儲(chǔ)在結(jié)果集或局部變量中 
  sp_oasetproperty 改變一個(gè)對(duì)象屬性的值 
  sp_oamethod 執(zhí)行對(duì)象的方法,向方法傳遞參數(shù),并得到返回值 
  sp_oastop 關(guān)閉sql server的自動(dòng)操作環(huán)境 
  表 1: sql server的com自動(dòng)操作存儲(chǔ)過(guò)程
com操作必須以調(diào)用sp_oacreate存儲(chǔ)過(guò)程開(kāi)始,語(yǔ)法格式如下所示:
sp_oacreate progid | clsid, objecttoken out.put,
第一個(gè)參數(shù)是程序id(progid━━一個(gè)應(yīng)用程序名.類名形式的字符串,例如:
excel.application,)或者一個(gè)類id(clsid━━一個(gè)nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn形式的全球唯一的id),它標(biāo)明你希望創(chuàng)建實(shí)例的com對(duì)象。
在可能的情況下,我建議使用progid參數(shù),因?yàn)樗子谳斎牒陀洃?。你?huì)發(fā)現(xiàn),只有很少的希望自動(dòng)操作的對(duì)象沒(méi)蠵rogid,如果偶爾碰上這樣的對(duì)象,就只有使用clsid了。第二個(gè)變量objecttoken也是一個(gè)整型變量,一個(gè)對(duì)象的標(biāo)記是指向sql server創(chuàng)建的對(duì)象的句柄和指針,我們需要在隨后的對(duì)對(duì)象的自動(dòng)操作中使用這個(gè)返回的對(duì)象標(biāo)記來(lái)確定這個(gè)對(duì)象。最后的context變量是可選的,可以強(qiáng)迫創(chuàng)建的對(duì)象使用某種自動(dòng)操作的機(jī)制。如果其值為1,則要求對(duì)象在一個(gè)activex dll文件中;值為4,則要求對(duì)象在activex exe服務(wù)器中;如果是缺省的值5,則可以使用任一自動(dòng)操作。在這里我們建議使用缺省的選項(xiàng),而無(wú)須為context參數(shù)提供一個(gè)恰當(dāng)?shù)闹?。下面調(diào)用op_oacreate 的命令將創(chuàng)建一個(gè)微軟的excel程序的實(shí)例:
declare @object int
declare @retval int
exec @retval=sp_oacreate 'excel.application',
@object output
  在創(chuàng)建一個(gè)對(duì)象后,需要獲取其一些屬性。要得到這些屬性,可以通過(guò)下面的語(yǔ)法調(diào)
  sp_oagetproperty:
  sp_oagetproperty objecttoken, propertyname[, propertyvalue output] [,第一個(gè)參數(shù)objecttoken的值就是由sp_oacreate返回的值,參數(shù)propertyname是我們希望獲取的屬性。
在獲取這個(gè)值是有幾種選擇,如果該屬性是一個(gè)單一的值,可以把它存儲(chǔ)在一個(gè)變量中,或者把它作為一個(gè)單行、單字段的結(jié)果集;如果屬性值是一個(gè)一維或二維的數(shù)組,則必須把它作為一個(gè)結(jié)果集;如果如果該屬性的值是一個(gè)多于二維的數(shù)組,sp_oagetproperty就不能返回它的值,會(huì)出現(xiàn)一個(gè)錯(cuò)誤。要返回一個(gè)結(jié)果集,只須簡(jiǎn)單地不指定propertyvalue參數(shù)的值即可(如果需要它有一個(gè)值以便使用index參數(shù),就把null賦給它好了。
否則的話,應(yīng)該賦給propertyvalue一個(gè)適當(dāng)?shù)念愋偷闹?,并且一定要把該參?shù)標(biāo)記為output。如果你訪問(wèn)的屬性是一個(gè)集合,就需要使用index參數(shù)指定這個(gè)集合中一個(gè)特定的數(shù)字。如果一個(gè)對(duì)象的屬性是另一個(gè)對(duì)象,就應(yīng)該把這個(gè)對(duì)象存入一個(gè)整數(shù)型變量中,sp_oagetproperty返回的也是一個(gè)對(duì)象標(biāo)記,不過(guò)與sp_oacreate返回的并不相同。我們可以使用這個(gè)對(duì)象標(biāo)記對(duì)存儲(chǔ)過(guò)程返回的任何對(duì)象進(jìn)行自動(dòng)化操作。下面的命令調(diào)用sp_oagetproperty把一個(gè)名字為defaultfilepath的屬性值存入變量@dfp中:
  exec sp_oagetproperty @object, 'defaultfilepath',
  @dfp output
可以通過(guò)如下格式使用sp_oasetproperty存儲(chǔ)過(guò)程改變一個(gè)對(duì)象的屬性值:
sp_oasetproperty objecttoken, propertyname,newvalue [, index]
第一個(gè)參數(shù)objecttoken是由sp_oacreate返回的,參數(shù)propertyname是要改變的對(duì)象的屬性名字,newvalue參數(shù)是想賦給屬性的新變量,可以是一個(gè)變量或一個(gè)文字值。如果設(shè)定的屬性值是作為一個(gè)集合的一個(gè)對(duì)象,可以使用可選的index參數(shù)來(lái)指定這個(gè)集合的一個(gè)特定的位置。下面的命令調(diào)用sp_oasetproperty把名字為fixeddecimalplaces的屬性設(shè)置為6:exec sp_oasetproperty @object, 'fixeddecimalplaces', 6
可以用下面的語(yǔ)法調(diào)用sp_oamethod存儲(chǔ)過(guò)程執(zhí)行一個(gè)對(duì)象的方法:
sp_oamethod objecttoken, methodname [, returnvalue output] [,
sp_oamethod是最靈活的,因而也是最復(fù)雜的自動(dòng)操作存儲(chǔ)過(guò)程,我們甚至可以用它象調(diào)用一個(gè)方法那樣調(diào)用一個(gè)屬性,而且還能得到一個(gè)返回值,當(dāng)然,我們也能使用sp_oagetproperty來(lái)完成這一任務(wù)。該存儲(chǔ)過(guò)程的第一個(gè)參數(shù)objecttoken是由sp_oacreate返回的對(duì)象標(biāo)記,參數(shù)methodname是希望執(zhí)行的方法的名字,如果該方法有返回值,則下一個(gè)參數(shù)returnvalue應(yīng)當(dāng)是一個(gè)包含該方法返回值的適當(dāng)類型的變量;如果返回值是一個(gè)一維或二維的數(shù)組,則用null作為一個(gè)占位符,該過(guò)程將返回一個(gè)結(jié)果集。該存儲(chǔ)過(guò)程不能返回一個(gè)超過(guò)二維的數(shù)組作為結(jié)果集合,在這種情況下,sql server就會(huì)出錯(cuò)。如果該方法沒(méi)有返回類型。
如果調(diào)用的方法需要參數(shù),就需要在調(diào)用sp_oamethod時(shí)提供這些參數(shù)。如果方法允許按順序提供參數(shù),則按要求的順序列出每個(gè)參數(shù),并用逗號(hào)分隔每個(gè)參數(shù),還可以用變量或文字變量作為參數(shù)。如果需要使用有名參數(shù),sql server也提供了相應(yīng)的機(jī)制,只需使用:@變量名=變量值 的形式列出所需的變量即可。需要注意的是不要因?yàn)橛蠤前綴而把變量名當(dāng)作局部變量,當(dāng)調(diào)用存儲(chǔ)過(guò)程sp_oamethod時(shí),sql server就會(huì)解析出@,因此,即使在調(diào)用的方法中有名字為hostname的參數(shù)時(shí),仍然可以使用名字為@hostname的局部變量。
下面是二個(gè)調(diào)用sp_oamethod的例子。第一個(gè)例子調(diào)用一個(gè)名字為centimeterstopoints的方法,它只接受在@cmval變量中提供的一個(gè)參數(shù),返回的值存儲(chǔ)在變量@retval中。第二個(gè)例子調(diào)用一個(gè)名字為maillogon的方法,它接受三個(gè)可選的變量,這個(gè)例子中根據(jù)名字接受二個(gè)變量,把name設(shè)置為字符串"myusername",把 password設(shè)置為字符串:
  exec sp_oamethod @object, 'centimeterstopoints',@retval output, @cmval
  exec sp_oamethod @object, 'maillogon', null,@name='myusername', 
不再使用一個(gè)對(duì)象后,需要通過(guò)下面的語(yǔ)法調(diào)用存儲(chǔ)過(guò)程sp_oadestroy釋放對(duì)該對(duì)象的引sp_oadestroy objecttoken
調(diào)用sp_oadestroy存儲(chǔ)過(guò)程可以釋放由參數(shù)objecttoken指定的對(duì)象,同時(shí)還釋放這個(gè)對(duì)象所使用的內(nèi)存和其他資源。下面是一個(gè)調(diào)用sp_oadestroy的命令:
exec sp_oadestroy @object
需要注意的是,t-sql中的數(shù)據(jù)類型與其他的編程語(yǔ)言并非是一一對(duì)應(yīng)的,在調(diào)用一個(gè)需要特定的數(shù)據(jù)類型的方法時(shí)就可能出錯(cuò)。"數(shù)據(jù)類型轉(zhuǎn)換"工具條可以將sql server的數(shù)據(jù)。
錯(cuò)誤處理
象在前面提到的那樣,如果對(duì)存儲(chǔ)過(guò)程的調(diào)用成功了,則會(huì)返回一個(gè)為0的hresult值,其他的hresult值則意味著發(fā)生了錯(cuò)誤。要判斷一個(gè)非零的hresult值,可以把hresult值傳:
sp_oageterrorinfo [objecttoken] [, source output] [, description output]
第一個(gè)參數(shù)objecttoken是由sp_oacreate返回的對(duì)象標(biāo)記。
下面的四個(gè)參數(shù)返回錯(cuò)誤信息。source是產(chǎn)生這一錯(cuò)誤信息的應(yīng)用程序或庫(kù),description是該錯(cuò)誤的描述,如果有幫助文件的話,則該helpfile是幫助文件的路徑。這三個(gè)參數(shù)都是有符號(hào)或無(wú)符號(hào)字符型數(shù)據(jù),sp_oageterrorinfo會(huì)根據(jù)定義的變量的大小截取返回的值。最后一個(gè)參數(shù)helpid是特定錯(cuò)誤在幫助文件中的索引號(hào)。下面的命令調(diào)用sp_oageterrorinfo以獲得某一個(gè)錯(cuò)誤的更詳細(xì)的信息:
declare @source varchar(100), @description varchar(255), @helpfile
exec sp_oageterrorinfo @object, @source output, @description output,
sql server在線手冊(cè)還提供了一個(gè)有關(guān)sp_displayoaerrorinfo存儲(chǔ)過(guò)程的例子,該存儲(chǔ)過(guò)程可以調(diào)用sp_oageterrorinfo把返回的值組織成格式化的字符串,以便把該信息寫(xiě)入日志文件中。
關(guān)于sp_displayoaerrorinfo的更詳細(xì)的信息,請(qǐng)參閱工具條, 另外,調(diào)用sp_oastop儲(chǔ)存過(guò)程可以關(guān)閉sql server的com自動(dòng)操作環(huán)境,它無(wú)需任何參數(shù)。關(guān)閉自動(dòng)操作環(huán)境在大多數(shù)情況下并非是必需的,第一次調(diào)用sp_oacreate時(shí)自動(dòng)操作環(huán)境會(huì)自動(dòng)開(kāi)啟,sql server關(guān)閉時(shí)自動(dòng)操作環(huán)境也會(huì)自動(dòng)關(guān)閉。如果一個(gè)存儲(chǔ)過(guò)程正在對(duì)一個(gè)對(duì)象進(jìn)行自動(dòng)操作,而另一個(gè)過(guò)程調(diào)用sp_oastop時(shí)就會(huì)出現(xiàn)錯(cuò)誤,因此我們不建議在程序中調(diào)用sp_oastop,只有在調(diào)試一個(gè)沒(méi)有運(yùn)行的過(guò)程時(shí),才可以通過(guò)一個(gè)查詢窗口調(diào)用它。
在實(shí)際工作中使用com自動(dòng)操作
  至此,我們已經(jīng)學(xué)習(xí)了如何使用每一個(gè)com自動(dòng)操作存儲(chǔ)過(guò)程,我們現(xiàn)在來(lái)討論一下一個(gè)綜合應(yīng)用它們的例子。程序清單1是一個(gè)名字為sp_openwordifcoprocavailable的過(guò)程,在這個(gè)過(guò)程中,我們用sp_oacreate創(chuàng)建了一個(gè)microsoft word的實(shí)例,然后使用sp_oagetproperty來(lái)獲取word的mathcoprocessoravailable屬性,如果sp_oagetproperty返回1,則sp_openwordifcoprocavailable向調(diào)用過(guò)程返回word對(duì)象的對(duì)象標(biāo)記;否則,
  sp_openwordifcoprocavailable關(guān)閉word,并返回0。為了節(jié)省版面,我們只調(diào)用了出錯(cuò)處理過(guò)程一次,在實(shí)際應(yīng)用中,應(yīng)該在每次調(diào)用自動(dòng)操作存儲(chǔ)過(guò)程后都調(diào)用出錯(cuò)處理過(guò)程。注意,為對(duì)word進(jìn)行自動(dòng)操作,應(yīng)該在安裝sql server的機(jī)器上安裝word。
程序清單 1:自動(dòng)操作word的方法的例子
create procedure sp_openwordifcoprocavailable as
declare @object int, @hr int, @retval intexec @hr = sp_oacreate 'word.application', @object output
begin
exec sp_displayoaerrorinfo @object, @hrreturn 0
end
exec @hr = sp_oagetproperty @object, 'mathcoprocessoravailable', @retval
if @hr=0
begin
exec @hr = sp_oamethod @object, 'quit', 0
exec @hr = sp_oadestroy @object
return 0
end
exec @hr = sp_oamethod @object, 'activate'return @object
如果需要對(duì)一個(gè)使用visual basic編寫(xiě)的com對(duì)象進(jìn)行自動(dòng)操作,調(diào)試它與sql server之間的互操作性是一件相當(dāng)容易的事。我們需要在運(yùn)行sql server的機(jī)器上安裝有visual basic,在visual basic的編輯器中加載com項(xiàng)目,設(shè)置一些斷點(diǎn),然后編譯并運(yùn)行該com對(duì)象。在有存儲(chǔ)過(guò)程對(duì)該對(duì)象進(jìn)行自動(dòng)操作時(shí),在運(yùn)行到一個(gè)斷點(diǎn)時(shí),編輯器就會(huì)自動(dòng)切換到調(diào)試模式,我們就可以象調(diào)試其他的visual basic程序那樣調(diào)試這個(gè)com對(duì)象。如果要對(duì)調(diào)試過(guò)程實(shí)施更多的控制,可以使用t-sql debugger for vb插件,它能采用步進(jìn)方式執(zhí)行存。
此外,在sql server中應(yīng)用com自動(dòng)操作我們還能作什么呢?下面是我曾使用sql server強(qiáng)大的com自動(dòng)操作功能的實(shí)際例子。前不久,我需要從一個(gè)sql server存儲(chǔ)過(guò)程中使用一個(gè)通過(guò)命名管道進(jìn)行通訊,而sql server中沒(méi)有提供通過(guò)編程方式打開(kāi)和使用命名管道的機(jī)制,我正好有一個(gè)可以使用命名管道通訊的vb例和庫(kù),因此就把這個(gè)庫(kù)文件作成一個(gè)類,并創(chuàng)建了一個(gè)activex dll文件,然后從存儲(chǔ)過(guò)程中對(duì)dll進(jìn)行自動(dòng)操作。
另一次,我需要復(fù)制一些文件和數(shù)據(jù)庫(kù)表。使用sql server的復(fù)制功能可以很方便地復(fù)制這些數(shù)據(jù),但復(fù)制文件則要難得多,nt的目錄同步功能很弱,不能滿足要求。盡管我還可以把拷貝命令存到字符變量中,然后把變量傳遞給xp_cmdshell,但會(huì)遇到命令行長(zhǎng)度的限制。更不方便的是,如果在拷貝過(guò)程中發(fā)生了錯(cuò)誤,我不能很方便地判斷錯(cuò)誤發(fā)生在什么地方,因此,我就編寫(xiě)了一個(gè)activex dll,并通過(guò)自動(dòng)操作它來(lái)處理文件的拷貝工作。
還有一次,我需要在sql server 6.5和index server 2.0之間先執(zhí)行連結(jié)后再完成查詢?nèi)蝿?wù),如果使用帶ado的windows 2000 indexing services和sql server 7.0,完成這樣的工作非常簡(jiǎn)單,但如果不是使用這些產(chǎn)品,則要困難得多。
首先,需要編寫(xiě)一個(gè)可以執(zhí)行index server查詢對(duì)象ixsso.dll的activex dll,對(duì)它進(jìn)行自動(dòng)操作,從index server目錄中獲得信息,并通過(guò)一個(gè)方法將信息返回到存儲(chǔ)過(guò)程中。
然后把這些數(shù)據(jù)保存到一個(gè)臨時(shí)表中,再對(duì)它進(jìn)行聯(lián)結(jié)操作。com自動(dòng)操作再一次幫我解決了問(wèn)題。在存儲(chǔ)過(guò)程中執(zhí)行com自動(dòng)操作幾乎可以使我們完成任何想完成的操作。sql server 2000中的com自動(dòng)操作沒(méi)有什么變化,因此采用這種方法編寫(xiě)的代碼在將來(lái)仍然可以使用下去。
新聞熱點(diǎn)
疑難解答
圖片精選