pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
在第 30.4 节中,你已经看到如何从嵌入式 SQL 程序中执行 SQL 语句。其中一些语句只使用固定值,既无法把用户提供的值插入语句中,也无法让程序处理查询返回的值。这类语句在实际应用中并不真正有用。本节将详细解释如何使用一种称为主变量的简单机制,在 C 程序与嵌入式 SQL 语句之间传递数据。
在嵌入式 SQL 中,在 C 程序和 SQL 语句之间传递数据特别简单。我们不必让程序把数据拼接进语句中去,那样会带来诸如正确为值加引号等各种复杂问题;只需在 SQL 语句中写出 C 变量的名称,并在前面加上一个冒号即可。例如:
EXEC SQL INSERT INTO sometable VALUES (:v1, 'foo', :v2);
该语句引用了两个名为v1和v2的 C 变量,同时还使用了一个普通的 SQL 字符串常量,以说明你并不局限于只使用某一种数据。
这种在 SQL 语句中插入 C 变量的方式可以用在 SQL 语句中每一个应该出现值表达式的地方。在 SQL 环境中,我们把对 C 变量的引用称为主变量。
要把数据从程序传给数据库(例如作为查询参数),或者把数据从数据库传回程序,用来承载这些数据的 C 变量必须声明在经过特殊标记的区段中,这样嵌入式 SQL 预处理器才能识别它们。
这个区段始于:
EXEC SQL BEGIN DECLARE SECTION;
并结束于:
EXEC SQL END DECLARE SECTION;
在这两行之间,必须是正常的 C 变量声明,例如:
int x; char foo[16], bar[16];
一个程序中可以根据需要放置任意多个声明节。
这些声明也会作为普通 C 变量声明写入输出文件,因此无需再次声明它们。不准备在 SQL 命令中使用的变量可以照常在这些特殊声明节之外声明。
结构体或联合的定义也必须写在DECLARE声明节中。否则预处理器无法处理这些类型,因为它不知道它们的定义。
特殊类型VARCHAR会被转换成每个变量的一个命名的struct。像这样的声明:
VARCHAR var[180];
会被转换为:
struct varchar_var { int len; char arr[180]; } var;
这个结构适合与varchar类型的 SQL 数据交互。
SELECT INTO与FETCH INTO现在你应该能够把程序产生的数据传递到一个 SQL 命令中了。但是怎么检索一个查询的结果呢?为此,嵌入式 SQL 提供了常规命令SELECT和FETCH的特殊变体。这些命令有一个特殊的INTO子句,它指定被检索到的值要被存储在哪些主变量中。
这里是一个例子:
/* * 假定有下列表: * CREATE TABLE test1 (a int, b varchar(50)); */ EXEC SQL BEGIN DECLARE SECTION; int v1; VARCHAR v2; EXEC SQL END DECLARE SECTION; ... EXEC SQL SELECT a, b INTO :v1, :v2 FROM test;
那么INTO子句出现在选择列表和FROM子句之间。选择列表中的元素数量必须和INTO后面列表(也被称为目标列表)的元素数量相等。
这里有一个使用命令FETCH的例子:
EXEC SQL BEGIN DECLARE SECTION;
int v1;
VARCHAR v2;
EXEC SQL END DECLARE SECTION;
...
EXEC SQL DECLARE foo CURSOR FOR SELECT a, b FROM test;
...
do
{
...
EXEC SQL FETCH NEXT FROM foo INTO :v1, :v2;
...
} while (...);
这里INTO子句出现在所有正常子句的后面。
上面这两种方法每次都只能检索单行数据。如果需要处理可能包含多于一行的结果集,就需要使用游标,如第二个示例所示。
上面的示例没有处理空值。实际上,如果读取示例从数据库取得空值,就会抛出错误。要向数据库传入空值或从数据库取得空值,需要在每个包含数据的主变量后,再指定第二个主变量。第二个主变量称为指示符,其中包含一个标志,表示该数据是否为空值;如果为空值,就会忽略实际主变量的值。下面的示例能正确处理空值的读取:
EXEC SQL BEGIN DECLARE SECTION; VARCHAR val; int val_ind; EXEC SQL END DECLARE SECTION: ... EXEC SQL SELECT b INTO :val :val_ind FROM test1;
指示符变量 val_ind 在数据非空时为零,在数据为空值时为负数。
指示符有另一种功能:如果指示符值为正,它表示值不为空,但是当它被存储在主变量中时已被截断。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。