本节介绍如何打开、关闭和切换数据库连接。
使用以下语句连接到数据库
EXEC SQL CONNECT TOtarget[ASconnection-name] [USERuser-name];
目标 可以通过以下方式指定
数据库名[@主机名][:端口]tcp:postgresql://主机名[:端口][/数据库名][?选项]unix:postgresql://[:端口][/数据库名][?选项]DEFAULT连接目标 DEFAULT 会在默认用户名下启动到一个默认数据库的连接。在这种情况下,不能指定单独的用户名或连接名。
如果您直接指定连接目标(即,不是作为字符串字面量或变量引用),则目标的组成部分将通过正常的 SQL 解析;这意味着,例如,主机名 必须看起来像一个或多个由点分隔的 SQL 标识符,并且除非加双引号,否则这些标识符将是大小写折叠的。任何 选项 的值必须是 SQL 标识符、整数或变量引用。当然,您可以通过加双引号将几乎任何内容放入 SQL 标识符中。实际上,使用(单引号)字符串字面量或变量引用可能比直接编写连接目标更不容易出错。
还有不同的指定用户名的方法
用户名用户名/密码用户名 IDENTIFIED BY 密码用户名 USING 密码与上面一样,用户名 和 密码 参数可以是 SQL 标识符、SQL 字符串字面量或字符变量的引用。
如果连接目标包含任何 选项,那么这些选项是由 规范组成的,并由和号(关键字=值&)分隔。允许的关键字与 libpq 识别的关键字相同(参见 第 32.1.2 节)。在任何 关键字 或 值 之前都会忽略空格,但在其内部或之后则不会。请注意,无法在 值 中写入 &。
请注意,当指定套接字连接(带有 unix: 前缀)时,主机名必须是 localhost。要选择一个非默认套接字目录,请在目标 选项 部分将目录的路径名作为 host 选项的值来编写。
连接名 用于处理程序中的多个连接。如果程序只使用一个连接,则可以省略它。最近打开的连接将成为当前连接,当执行 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 变量可以在 SQL 语句中使用。
请注意,连接目标的格式未在 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 标识符链接到连接,就可以在没有 AT 子句的情况下执行动态 SQL。请注意,此选项的行为类似于预处理器指令,因此链接仅在该文件中启用。
以下是使用此选项的示例程序
#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];
连接 可以通过以下方式指定
连接名CURRENTALL如果未指定连接名,则会关闭当前连接。
应用程序最好始终显式断开它打开的所有连接。