本节描述如何打开、关闭和切换数据库连接。
可以使用以下语句连接到数据库
EXEC SQL CONNECT TOtarget[ASconnection-name] [USERuser-name];
target 可以通过以下方式指定
dbname[@hostname][:port]tcp:postgresql://hostname[:port][/dbname][?options]unix:postgresql://[:port][/dbname][?options]DEFAULT连接目标 DEFAULT 启动与默认用户名下的默认数据库的连接。在这种情况下,不能指定单独的用户名或连接名。
如果您直接指定连接目标(即,不是作为字符串字面量或变量引用),则目标的组成部分将通过正常的 SQL 解析传递;这意味着,例如,hostname 必须看起来像一个或多个由点分隔的 SQL 标识符,并且这些标识符将进行大小写折叠,除非用双引号引起来。options 的任何值都必须是 SQL 标识符、整数或变量引用。当然,您可以通过用双引号将其引起来,将几乎任何内容放入 SQL 标识符中。实际上,使用(单引号)字符串字面量或变量引用可能比直接编写连接目标更不容易出错。
还有不同的方法来指定用户名
usernameusername/passwordusername IDENTIFIED BY passwordusername USING password如上所述,参数 username 和 password 可以是 SQL 标识符、SQL 字符串字面量或对字符变量的引用。
如果连接目标包含任何 options,则这些 规范由 & 符号 (keyword=value&) 分隔。允许的关键字与 libpq 识别的关键字相同 (请参阅 第 32.1.2 节)。在任何 keyword 或 value 之前会忽略空格,但不在其中或之后。请注意,无法在 value 中写入 &。
请注意,当指定套接字连接(使用 unix: 前缀)时,主机名必须完全是 localhost。要选择非默认的套接字目录,请将该目录的路径名写为目标 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; */
最后一个示例利用了上面称为字符变量引用的特性。在后面的章节中,您将看到如何在 SQL 语句中使用 C 变量,方法是在它们前面加上冒号。
请注意,连接目标的格式未在 SQL 标准中指定。因此,如果您想开发可移植的应用程序,您可能希望使用基于上述最后一个示例的东西,将连接目标字符串封装在某个地方。
如果不受信任的用户可以访问未采用安全模式使用模式的数据库,请通过从 search_path 中删除可公开写入的模式来开始每个会话。例如,将 options=-c search_path= 添加到 ,或在连接后执行 optionsEXEC SQL SELECT pg_catalog.set_config('search_path', '', false);。此注意事项并非特定于 ECPG;它适用于执行任意 SQL 命令的每个接口。
嵌入式 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 ATconnection-nameDECLAREstatement-nameSTATEMENT; EXEC SQL PREPAREstatement-nameFROM :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
要关闭连接,请使用以下语句
EXEC SQL DISCONNECT [connection];
connection 可以通过以下方式指定
connection-nameCURRENTALL如果未指定连接名称,则会关闭当前连接。
应用程序始终显式断开其打开的每个连接是一种好的风格。
如果您发现文档中任何不正确、与您使用特定功能的体验不符或需要进一步澄清的内容,请使用此表格报告文档问题。