ECPG 對 C++ 應用程式有一些有限的支援。本節描述了一些注意事項。
ecpg
前置處理器採用以 C 語言(或類似 C 語言)和嵌入式 SQL 命令編寫的輸入檔案,將嵌入式 SQL 命令轉換為 C 語言區塊,最後產生一個 .c
檔案。當在 C++ 中使用時,ecpg
產生的 C 語言區塊使用的函式庫函式標頭檔案宣告會包裝在 extern "C" { ... }
區塊中,因此它們應該可以在 C++ 中無縫運作。
然而,一般來說,ecpg
前置處理器只理解 C 語言;它不處理 C++ 語言的特殊語法和保留字。因此,在 C++ 應用程式程式碼中編寫的一些使用 C++ 特有複雜功能的嵌入式 SQL 程式碼,可能無法正確地進行前置處理,或者可能無法如預期運作。
在 C++ 應用程式中使用嵌入式 SQL 程式碼的安全方法是將 ECPG 呼叫隱藏在 C 模組中,C++ 應用程式程式碼呼叫該模組以存取資料庫,並將其與其餘的 C++ 程式碼連結在一起。有關此資訊,請參閱第 34.13.2 節。
ecpg
前置處理器瞭解 C 語言中變數的作用域。在 C 語言中,這相當簡單,因為變數的作用域基於其程式碼區塊。然而,在 C++ 中,類別成員變數從宣告位置的不同程式碼區塊中引用,因此 ecpg
前置處理器將不瞭解類別成員變數的作用域。
例如,在以下情況中,ecpg
前置處理器無法在 test
方法中找到變數 dbname
的任何宣告,因此會發生錯誤。
class TestCpp { EXEC SQL BEGIN DECLARE SECTION; char dbname[1024]; EXEC SQL END DECLARE SECTION; public: TestCpp(); void test(); ~TestCpp(); }; TestCpp::TestCpp() { EXEC SQL CONNECT TO testdb1; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; } void Test::test() { EXEC SQL SELECT current_database() INTO :dbname; printf("current_database = %s\n", dbname); } TestCpp::~TestCpp() { EXEC SQL DISCONNECT ALL; }
此程式碼將導致類似以下的錯誤
ecpg test_cpp.pgc
test_cpp.pgc:28: ERROR: variable "dbname" is not declared
為了避免此作用域問題,可以修改 test
方法以使用區域變數作為中介儲存。但是,此方法只是一種不好的解決方案,因為它會醜化程式碼並降低效能。
void TestCpp::test() { EXEC SQL BEGIN DECLARE SECTION; char tmp[1024]; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT current_database() INTO :tmp; strlcpy(dbname, tmp, sizeof(tmp)); printf("current_database = %s\n", dbname); }
如果您瞭解 C++ 中 ecpg
前置處理器的這些技術限制,您可能會得出結論,在連結階段連結 C 物件和 C++ 物件,以使 C++ 應用程式能夠使用 ECPG 功能,可能比直接在 C++ 程式碼中編寫一些嵌入式 SQL 命令更好。本節描述了一種使用簡單範例將一些嵌入式 SQL 命令與 C++ 應用程式程式碼分離的方法。在此範例中,應用程式以 C++ 實作,而 C 和 ECPG 用於連接到 PostgreSQL 伺服器。
必須建立三種檔案:C 檔案 (*.pgc
)、標頭檔案和 C++ 檔案
test_mod.pgc
#一個子常式模組,用於執行嵌入在 C 中的 SQL 命令。它將由前置處理器轉換為 test_mod.c
。
#include "test_mod.h" #include <stdio.h> void db_connect() { EXEC SQL CONNECT TO testdb1; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; } void db_test() { EXEC SQL BEGIN DECLARE SECTION; char dbname[1024]; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT current_database() INTO :dbname; printf("current_database = %s\n", dbname); } void db_disconnect() { EXEC SQL DISCONNECT ALL; }
test_mod.h
#一個標頭檔案,其中包含 C 模組 (test_mod.pgc
) 中函式的宣告。它由 test_cpp.cpp
包含。此檔案必須在宣告周圍有一個 extern "C"
區塊,因為它將從 C++ 模組連結。
#ifdef __cplusplus extern "C" { #endif void db_connect(); void db_test(); void db_disconnect(); #ifdef __cplusplus } #endif
test_cpp.cpp
#應用程式的主要程式碼,包括 main
常式,在本範例中是一個 C++ 類別。
#include "test_mod.h" class TestCpp { public: TestCpp(); void test(); ~TestCpp(); }; TestCpp::TestCpp() { db_connect(); } void TestCpp::test() { db_test(); } TestCpp::~TestCpp() { db_disconnect(); } int main(void) { TestCpp *t = new TestCpp(); t->test(); return 0; }
若要建置應用程式,請按以下步驟進行。透過執行 ecpg
將 test_mod.pgc
轉換為 test_mod.c
,並透過使用 C 編譯器編譯 test_mod.c
來產生 test_mod.o
ecpg -o test_mod.c test_mod.pgc cc -c test_mod.c -o test_mod.o
接下來,透過使用 C++ 編譯器編譯 test_cpp.cpp
來產生 test_cpp.o
c++ -c test_cpp.cpp -o test_cpp.o
最後,使用 C++ 編譯器驅動程式將這些物件檔案 test_cpp.o
和 test_mod.o
連結到一個可執行檔中
c++ test_cpp.o test_mod.o -lecpg -o test_cpp
如果您在文件中看到任何不正確、與特定功能的使用體驗不符或需要進一步說明的內容,請使用 此表單 回報文件問題。