支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不再支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3

34.2. 管理資料庫連線 #

本節描述如何開啟、關閉及切換資料庫連線。

34.2.1. 連接到資料庫伺服器 #

使用以下敘述來連接到資料庫

EXEC SQL CONNECT TO target [AS connection-name] [USER user-name];

可以使用下列方式指定 target

  • dbname[@hostname][:port]
  • tcp:postgresql://hostname[:port][/dbname][?options]
  • unix:postgresql://127.0.0.1[:port][/dbname][?options]
  • 包含上述形式之一的 SQL 字串常值
  • 對包含上述形式之一的字元變數的參考 (請參閱範例)
  • DEFAULT

連線目標 DEFAULT 會以預設使用者名稱啟動與預設資料庫的連線。 在這種情況下,無法指定個別的使用者名稱或連線名稱。

如果直接指定連線目標 (也就是說,不是作為字串常值或變數參考),則目標的組成部分會經過正常的 SQL 剖析;這表示,例如,hostname 必須看起來像一個或多個以點分隔的 SQL 識別符,並且這些識別符會被摺疊成小寫,除非用雙引號括起來。 任何 options 的值都必須是 SQL 識別符、整數或變數參考。 當然,您可以透過雙引號將幾乎任何內容放入 SQL 識別符中。 實際上,使用 (單引號) 字串常值或變數參考可能比直接編寫連線目標更不容易出錯。

還有不同的方法可以指定使用者名稱

  • username
  • username/password
  • username IDENTIFIED BY password
  • username USING password

如上所述,參數 usernamepassword 可以是 SQL 識別符、SQL 字串常值或字元變數的參考。

如果連線目標包含任何 options,則這些選項由以 & 符號 (&) 分隔的 keyword=value 規格組成。 允許的關鍵字與 libpq 辨識的關鍵字相同 (請參閱第 32.1.2 節)。 任何 keywordvalue 前面的空格都會被忽略,但不在其中或之後。 請注意,沒有辦法在 value 中編寫 &

請注意,在指定 Socket 連線 (使用 unix: 前綴) 時,主機名稱必須完全是 localhost。 若要選取非預設 Socket 目錄,請將目錄的路徑名稱寫為目標 options 部分中 host 選項的值。

connection-name 用於在一個程式中處理多個連線。 如果程式僅使用一個連線,則可以省略它。 最近開啟的連線會變成目前的連線,預設情況下會在執行 SQL 敘述時使用 (請參閱本章後面的內容)。

以下是一些 CONNECT 敘述的範例

EXEC SQL CONNECT TO mydb@sql.mydomain.com;

EXEC SQL CONNECT TO tcp:postgresql://sql.mydomain.com/mydb AS myconnection USER john;

EXEC SQL BEGIN DECLARE SECTION;
const char *target = "mydb@sql.mydomain.com";
const char *user = "john";
const char *passwd = "secret";
EXEC SQL END DECLARE SECTION;
 ...
EXEC SQL CONNECT TO :target USER :user USING :passwd;
/* or EXEC SQL CONNECT TO :target USER :user/:passwd; */

最後一個範例使用了上述稱為字元變數參照的功能。您將在後面的章節中看到,當您在 C 變數前加上冒號時,C 變數如何在 SQL 陳述式中使用。

請注意,連線目標的格式並未在 SQL 標準中指定。因此,如果您想開發可移植的應用程式,您可能希望使用基於上述最後一個範例的方法,將連線目標字串封裝在某處。

如果不可信任的使用者可以存取未採用安全結構描述使用模式的資料庫,請在每個會話開始時,從 search_path 中移除可公開寫入的結構描述。例如,將 options=-c search_path= 新增至 options,或者在連線後發出 EXEC SQL SELECT pg_catalog.set_config('search_path', '', false);。這個考量並非 ECPG 獨有;它適用於執行任意 SQL 命令的每個介面。

34.2.2. 選擇連線 #

嵌入式 SQL 程式中的 SQL 陳述式預設在目前的連線上執行,也就是最近開啟的連線。如果應用程式需要管理多個連線,則有三種方法可以處理此問題。

第一種選擇是為每個 SQL 陳述式明確選擇一個連線,例如

EXEC SQL AT connection-name SELECT ...;

如果應用程式需要在混合順序中使用多個連線,則此選項特別合適。

如果您的應用程式使用多個執行緒,則它們不能同時共享一個連線。您必須明確控制對連線的存取(使用互斥鎖)或為每個執行緒使用一個連線。

第二種選擇是執行陳述式來切換目前的連線。該陳述式是

EXEC SQL SET CONNECTION connection-name;

如果要對同一個連線執行許多陳述式,此選項特別方便。

以下是一個管理多個資料庫連線的範例程式

#include <stdio.h>

EXEC SQL BEGIN DECLARE SECTION;
    char dbname[1024];
EXEC SQL END DECLARE SECTION;

int
main()
{
    EXEC SQL CONNECT TO testdb1 AS con1 USER testuser;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
    EXEC SQL CONNECT TO testdb2 AS con2 USER testuser;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
    EXEC SQL CONNECT TO testdb3 AS con3 USER testuser;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;

    /* This query would be executed in the last opened database "testdb3". */
    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb3)\n", dbname);

    /* Using "AT" to run a query in "testdb2" */
    EXEC SQL AT con2 SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb2)\n", dbname);

    /* Switch the current connection to "testdb1". */
    EXEC SQL SET CONNECTION con1;

    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current=%s (should be testdb1)\n", dbname);

    EXEC SQL DISCONNECT ALL;
    return 0;
}

此範例將產生以下輸出

current=testdb3 (should be testdb3)
current=testdb2 (should be testdb2)
current=testdb1 (should be testdb1)

第三種選擇是宣告一個連結到連線的 SQL 識別符,例如

EXEC SQL AT connection-name DECLARE statement-name STATEMENT;
EXEC SQL PREPARE statement-name FROM :dyn-string;

將 SQL 識別符連結到連線後,您可以執行動態 SQL 而無需 AT 子句。請注意,此選項的行為類似於前置處理器指令,因此連結僅在檔案中啟用。

以下是使用此選項的範例程式

#include <stdio.h>

EXEC SQL BEGIN DECLARE SECTION;
char dbname[128];
char *dyn_sql = "SELECT current_database()";
EXEC SQL END DECLARE SECTION;

int main(){
  EXEC SQL CONNECT TO postgres AS con1;
  EXEC SQL CONNECT TO testdb AS con2;
  EXEC SQL AT con1 DECLARE stmt STATEMENT;
  EXEC SQL PREPARE stmt FROM :dyn_sql;
  EXEC SQL EXECUTE stmt INTO :dbname;
  printf("%s\n", dbname);

  EXEC SQL DISCONNECT ALL;
  return 0;
}

即使預設連線是 testdb,此範例也會產生以下輸出

postgres

34.2.3. 關閉連線 #

要關閉連線,請使用以下陳述式

EXEC SQL DISCONNECT [connection];

connection 可以通過以下方式指定

  • 連線名稱
  • CURRENT
  • ALL

如果未指定連線名稱,則關閉目前的連線。

應用程式始終顯式地斷開與其開啟的每個連線的連線是一種良好的風格。

提交更正

如果您在文件中發現任何不正確、與您特定功能的經驗不符或需要進一步澄清的地方,請使用此表單報告文件問題。