共用方式為


程序設計 資料庫引擎擴充預存程式

適用於:SQL Server

重要

SQL Server 的未來版本將移除此功能。 請避免在新的開發工作中使用這項功能,並規劃修改目前使用這項功能的應用程式。 請改用 CLR 整合

擴充預存程序的運作方式

擴充預存程式運作的程式如下:

  1. 當用戶端執行擴充預存程式時,要求會以表格式數據流 (TDS) 或 Simple Object Access Protocol (SOAP) 格式從用戶端應用程式傳輸至 SQL Server。

  2. SQL Server 會搜尋與擴充預存程式相關聯的 DLL,如果尚未載入 DLL,則會載入 DLL。

  3. SQL Server 會呼叫要求的擴充預存程式(實作為 DLL 內的函式)。

  4. 擴充預存程式會透過擴充預存程式 API 將結果集傳回伺服器,並傳回參數。

過去,Open Data Services 用來將伺服器應用程式寫入,例如閘道到非 SQL Server 資料庫環境。 SQL Server 不支援 Open Data Services API 的過時部分。 SQL Server 仍然支援原始 Open Data Services API 的唯一部分是擴充預存程式函式,因此 API 已重新命名為擴充預存程式 API。

隨著分散式查詢和 CLR 整合的出現,擴充預存程式 API 應用程式的需求已基本取代。

如果您有現有的閘道應用程式,則無法使用 opends60.dll 隨附於 SQL Server 的 來執行應用程式。 不再支援閘道應用程式。

擴充預存程式與 CLR 整合

CLR 整合提供更強固的替代方式,可用來撰寫難以表達或無法在 Transact-SQL 中寫入的伺服器端邏輯。 在舊版的 SQL Server 中,擴充預存程式 (XPs) 提供了唯一可供資料庫應用程式開發人員撰寫這類程式代碼的機制。

使用 CLR 整合時,以預存程式形式撰寫的邏輯通常會更能以數據表值函式表示,這可讓函式在語句FROMSELECT內嵌結果,以查詢這些結果。

如需詳細資訊,請參閱 CLR 整合概觀

擴充預存程式的執行特性

擴充預存程式的執行具有下列特性:

  • 擴充預存程式函式會在 SQL Server 的安全性內容下執行。

  • 擴充預存程式函式會在 SQL Server 的進程空間中執行。

  • 與執行擴充預存程式相關聯的線程,與客戶端連接所使用的線程相同。

重要

將擴充預存程式新增至伺服器並將執行許可權授與其他使用者之前,系統管理員應該徹底檢閱每個擴充預存程式,以確保它不包含有害或惡意代碼。

載入擴充預存程式 DLL 之後,DLL 會保留在伺服器的位址空間中載入,直到 SQL Server 停止或系統管理員使用 DBCC <DLL_name> (FREE)明確卸除 DLL 為止。

擴充預存程式可以使用 語句,從 Transact-SQL 執行為預存程式 EXECUTE

EXECUTE @retval = xp_extendedProcName @param1, @param2 OUTPUT;

參數

@ retval

傳回值。

@ param1

輸入參數。

@ param2

輸入/輸出參數。

警告

擴充預存程式提供效能增強功能,並擴充 SQL Server 功能。 不過,由於擴充預存程式 DLL 和 SQL Server 共用相同的地址空間,因此問題程式可能會對 SQL Server 運作造成負面影響。 雖然擴充預存程式 DLL 擲回的例外狀況是由 SQL Server 處理,但可能會損毀 SQL Server 數據區域。 基於安全性預防措施,只有 SQL Server 系統管理員可以將擴充預存程式新增至 SQL Server。 這些程式應該在安裝之前經過徹底測試。

使用擴充預存程式 API 將結果集傳送至伺服器

將結果集傳送至 SQL Server 時,擴充預存程式應該呼叫適當的 API,如下所示:

  • 在所有資料列之前或之後,都可以依任何順序呼叫函 srv_sendmsg 式(如果有的話)與 srv_sendrow。 所有訊息都必須傳送至用戶端,才能使用 srv_senddone傳送完成狀態。

  • 針對傳送至用戶端的每個數據列,呼叫函 srv_sendrow 式一次。 所有數據列都必須傳送到客戶端,然後才能傳送任何訊息、狀態值或完成狀態,以及 srv_sendmsgsrv_status 、 或srv_senddonesrv_pfield自變數。

  • 傳送未定義 srv_describe 其所有數據行的數據列,會導致應用程式引發參考錯誤訊息,並返回 FAIL 用戶端。 在此情況下,不會傳送數據列。

建立擴充預存程式

擴充預存程式是具有原型的 C/C++ 函式:

SRVRETCODE xp_extendedProcName (SRVPROC *):

使用前置詞 xp_ 是選擇性的。 在 Transact-SQL 語句中參考時,不論伺服器上安裝的代碼頁/排序順序為何,擴充預存程式名稱都會區分大小寫。 當您建置 DLL 時:

  • 如果需要進入點,請撰寫函 DllMain 式。

    此函式是選擇性的。 如果您未在原始程式碼中提供,編譯程式會連結自己的版本,但不會傳回 TRUE。 如果您提供函 DllMain 式,當線程或進程附加至 DLL 或中斷連結時,操作系統會呼叫此函式。

  • 必須匯出從 DLL 外部呼叫的所有函式(所有擴充預存程式 Efunctions)。

    您可以藉由在 EXPORTS 檔案的 .def 區段中列出函式名稱來匯出函式,也可以將原始程式碼中的函式名稱前面加上 __declspec(dllexport)、Microsoft編譯程式延伸模組(__declspec() 開頭為兩個底線)。

建立擴充預存程式 DLL 需要這些檔案。

檔案 說明
srv.h 擴充預存程式 API 頭檔
opends60.lib 的匯入連結庫 opends60.dll

若要建立擴充預存程式 DLL,請建立動態連結庫類型的專案。 如需建立 DLL 的詳細資訊,請參閱開發環境檔。

所有擴充預存程式 DLL 都應該實作並匯出下列函式:

__declspec(dllexport) ULONG __GetXpVersion()
{
   return ODS_VERSION;
}

__declspec(dllexport) 是Microsoft特定的編譯程式延伸模組。 如果您的編譯程式不支援此指示詞,您應該在 區段下的 EXPORTS 檔案中DEF匯出此函式。

當 SQL Server 以追蹤旗標 -T260 啟動,或具有系統管理員許可權的使用者執行 DBCC TRACEON (260)時,如果擴充預存程式 DLL 不支援 __GetXpVersion(),則會將下列警告訊息列印至錯誤記錄檔(__GetXpVersion() 開頭為兩個底線)。

Error 8131: Extended stored procedure DLL '%' does not export __GetXpVersion().

如果擴充預存程式 DLL 匯出 __GetXpVersion(),但函式傳回的版本小於伺服器所需的版本,則會出現警告訊息,指出函式所傳回的版本,而伺服器預期的版本會列印至錯誤記錄檔。 如果您收到此訊息,您會從 __GetXpVersion()傳回不正確的值,或是使用舊版 的 srv.h編譯。

注意

SetErrorMode,Win32 函式,不應該在擴充預存程式中呼叫。

長時間執行的擴充預存程式應該定期呼叫 srv_got_attention ,如此一來,如果連接終止,或批次中止,程式就可以自行終止。

若要偵錯擴充預存程式 DLL,請將它複製到 SQL Server \Binn 目錄。 若要指定偵錯工作階段的可執行檔,請輸入 SQL Server 可執行檔案的路徑和檔案名(例如 , C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\Binn\sqlservr.exe。 如需自變數的相關信息 sqlservr ,請參閱 sqlservr Application

將擴充預存程式新增至 SQL Server

包含擴充預存程式函式的 DLL,可作為 SQL Server 的延伸模組。 若要安裝 DLL,請將檔案複製到目錄,例如包含標準 SQL Server DLL 檔案的檔案(C:\Program Files\Microsoft SQL Server\MSSQL16.0.<x>\MSSQL\Binn 預設為 )。

將擴充預存程式 DLL 複製到伺服器之後,SQL Server 系統管理員必須在 DLL 中向 SQL Server 註冊每個擴充預存程式函式。 這是使用 sp_addextendedproc 系統預存程式完成的。

重要

系統管理員應該徹底檢閱擴充預存程式,以確保它不包含有害或惡意代碼,再將它新增至伺服器,並將執行許可權授與其他使用者。 驗證所有使用者輸入。 在驗證之前,請勿串連用戶輸入。 請勿執行由未經驗證之使用者輸入所建構的命令。

的第一個參數 sp_addextendedproc 會指定函式的名稱,而第二個參數會指定該函式所在的 DLL 名稱。 您應該指定 DLL 的完整路徑。

注意

升級至 SQL Server 2005 (9.x) 或更新版本之後,未向完整路徑註冊的現有 DLL 無法運作。 若要更正問題,請使用 sp_dropextendedproc 取消註冊 DLL,然後重新註冊並 sp_addextendedproc, 指定完整路徑。

中指定的 sp_addextendedproc 函式名稱必須與 DLL 中的函式名稱完全相同,包括大小寫。 例如,此命令會將位於名為 xp_hello.dll的 dll 中的函xp_hello,式註冊為 SQL Server 擴充預存程式:

sp_addextendedproc 'xp_hello', 'c:\Program Files\Microsoft SQL Server\MSSQL13.0.MSSQLSERVER\MSSQL\Binn\xp_hello.dll';

如果 中指定的 sp_addextendedproc 函式名稱與 DLL 中的函式名稱不完全相符,新名稱會在 SQL Server 中註冊,但名稱無法使用。 例如,雖然 xp_Hello 註冊為位於 的 xp_hello.dllSQL Server 擴充預存程式,但如果您稍後使用 xp_Hello 呼叫函式,SQL Server 在 DLL 中找不到函式。

-- Register the function (xp_hello) with an initial upper case
sp_addextendedproc 'xp_Hello', 'c:\xp_hello.dll';

-- Use the newly registered name to call the function
DECLARE @txt VARCHAR(33);
EXEC xp_Hello @txt OUTPUT;

以下是錯誤訊息:

Server: Msg 17750, Level 16, State 1, Procedure xp_Hello, Line 1
Could not load the DLL xp_hello.dll, or one of the DLLs it references. Reason: 127(The specified procedure could not be found.).

如果 中指定的 sp_addextendedproc 函式名稱完全符合 DLL 中的函數名稱,且 SQL Server 實例的定序不區分大小寫,則使用者可以使用名稱中小寫和大寫字母的任何組合來呼叫擴充預存程式。

-- Register the function (xp_hello)
sp_addextendedproc 'xp_hello', 'c:\xp_hello.dll';

-- The following example succeeds in calling xp_hello
DECLARE @txt VARCHAR(33);
EXEC xp_Hello @txt OUTPUT;

DECLARE @txt VARCHAR(33);
EXEC xp_HelLO @txt OUTPUT;

DECLARE @txt VARCHAR(33);
EXEC xp_HELLO @txt OUTPUT;

當 SQL Server 實例的定序區分大小寫時,如果以不同的大小寫呼叫程式,SQL Server 就無法呼叫擴充預存程式。 即使它註冊的名稱和定序與 DLL 中的函式完全相同,也是如此。

-- Register the function (xp_hello)
sp_addextendedproc 'xp_hello', 'c:\xp_hello.dll';

-- The following example results in an error
DECLARE @txt VARCHAR(33);
EXEC xp_HELLO @txt OUTPUT;

以下是錯誤訊息:

Server: Msg 2812, Level 16, State 62, Line 1

您不需要停止並重新啟動 SQL Server。

查詢 SQL Server 中安裝的擴充預存程式

SQL Server 已驗證的使用者可以藉由執行 sp_helpextendedproc 系統程式,來顯示目前定義的擴充預存程式,以及每個預存程式所屬的 DLL 名稱。 例如,下列範例會傳回所屬的 xp_hello DLL:

sp_helpextendedproc 'xp_hello';

如果在 sp_helpextendedproc 未指定擴充預存程序的情況下執行,則會顯示所有擴充預存程式及其 DLL。

從 SQL Server 移除擴充預存程式

若要在使用者定義的擴充預存程式 DLL 中卸除每個擴充預存程式函式,SQL Server 系統管理員必須執行 sp_dropextendedproc 系統預存程式,並指定函式的名稱以及該函式所在的 DLL 名稱。 例如,此命令會從 SQL Server 移除名為 xp_hello.dll, 的 DLL 中的 函xp_hello式:

sp_dropextendedproc 'xp_hello';

sp_dropextendedproc 不會卸除系統擴充預存程式。 相反地,系統管理員應該拒絕將擴充預存程式的許可權授 EXECUTE公用 角色。

卸除擴充預存程式 DLL

SQL Server 會在呼叫 DLL 的其中一個函式時,立即載入擴充預存程式 DLL。 DLL 會維持載入狀態,直到伺服器關機或系統管理員使用 DBCC 語句卸除為止。 例如,此命令會 xp_hello.dll卸除 ,讓系統管理員將較新版本的這個檔案複製到目錄,而不需要關閉伺服器:

DBCC xp_hello(FREE);