选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0
历史版本PostgreSQL 9.0 已于 2015 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

33.6. 使用主变量 #

第 33.4 节中,你已经看到如何从嵌入式 SQL 程序中执行 SQL 语句。其中一些语句只使用固定值,既无法把用户提供的值插入语句中,也无法让程序处理查询返回的值。这类语句在实际应用中并不真正有用。本节将详细解释如何使用一种称为主变量的简单机制,在 C 程序与嵌入式 SQL 语句之间传递数据。在嵌入式 SQL 程序中,我们把 SQL 语句视为 C 程序代码中的客体,而 C 是主语言。因此,C 程序中的变量被称为主变量

33.6.1. 概述

在嵌入式 SQL 中,在 C 程序和 SQL 语句之间传递数据特别简单。我们不必让程序把数据拼接进语句中去,那样会带来诸如正确为值加引号等各种复杂问题;只需在 SQL 语句中写出 C 变量的名称,并在前面加上一个冒号即可。例如:

EXEC SQL INSERT INTO sometable VALUES (:v1, 'foo', :v2);

该语句引用了两个名为v1v2的 C 变量,同时还使用了一个普通的 SQL 字符串常量,以说明你并不局限于只使用某一种数据。

这种在 SQL 语句中插入 C 变量的方式可以用在 SQL 语句中每一个应该出现值表达式的地方。

33.6.2. 声明节

要把数据从程序传给数据库(例如作为查询参数),或者把数据从数据库传回程序,用来承载这些数据的 C 变量必须声明在经过特殊标记的区段中,这样嵌入式 SQL 预处理器才能识别它们。

这个区段始于:

EXEC SQL BEGIN DECLARE SECTION;

并结束于:

EXEC SQL END DECLARE SECTION;

在这两行之间,必须是正常的 C 变量声明,例如:

int   x = 4;
char  foo[16], bar[16];

如你所见,可以选择为变量指定初始值。变量的作用域由其声明节在程序中的位置决定。你也可以使用下面的语法声明变量,这种写法会隐式创建一个声明节:

EXEC SQL int i = 4;

一个程序中可以根据需要放置任意多个声明节。

这些声明也会作为普通 C 变量声明写入输出文件,因此无需再次声明它们。不准备在 SQL 命令中使用的变量可以照常在这些特殊声明节之外声明。

结构体或联合的定义也必须写在DECLARE声明节中。否则预处理器无法处理这些类型,因为它不知道它们的定义。

33.6.3. 不同类型的主变量

你也可以把数组、typedef、结构体和指针用作主变量。此外,还存在一些只在 ECPG 中使用的特殊类型的主变量。

下面是主变量的一些例子:

Arrays

数组声明最常见的用途之一可能就是像这样分配一个 char 数组:

EXEC SQL BEGIN DECLARE SECTION;
    char str[50];
EXEC SQL END DECLARE SECTION;

注意你必须自己处理长度。如果你把这个主变量用作一个返回多于 49 个字符的字符串的查询的目标变量,就会发生缓冲区溢出。

Typedefs

使用 typedef 关键字将新类型映射到已有类型。

EXEC SQL BEGIN DECLARE SECTION;
    typedef char mychartype[40];
    typedef long serial_t;
EXEC SQL END DECLARE SECTION;

注意,也可以使用:

EXEC SQL TYPE serial_t IS long;

此声明不必放在声明区段内。

Pointers

你可以声明指向最常见类型的指针。但要注意,只有使用自动内存分配时,才能将指针用作查询的目标变量。关于自动内存分配的更多信息,参见第 33.9 节

EXEC SQL BEGIN DECLARE SECTION;
    int   *intp;
    char **charp;
EXEC SQL END DECLARE SECTION;
特殊类型的主变量

ECPG 包含一些特殊类型,帮助你轻松地与来自 SQL 服务器的数据交互。例如,它实现了对varcharnumericdatetimestampinterval类型的支持。第 33.8 节包含处理这些类型的基本函数,这样例如你就不需要仅仅为了把一个区间加到一个时间戳上而向 SQL 服务器发送一个查询。

特殊类型VARCHAR会被转换成每个变量的一个命名的struct。像这样的声明:

VARCHAR var[180];

会被转换为:

struct varchar_var { int len; char arr[180]; } var;

这个结构适合与varchar类型的 SQL 数据交互。

33.6.4. SELECT INTOFETCH INTO

现在你应该能够把程序产生的数据传递到一个 SQL 命令中了。但是怎么检索一个查询的结果呢?为此,嵌入式 SQL 提供了常规命令SELECTFETCH的特殊变体。这些命令有一个特殊的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子句出现在所有正常子句的后面。

33.6.5. 指示符

上面的示例没有处理空值。实际上,如果读取示例从数据库取得空值,就会抛出错误。要向数据库传入空值或从数据库取得空值,需要在每个包含数据的主变量后,再指定第二个主变量。第二个主变量称为指示符,其中包含一个标志,表示该数据是否为空值;如果为空值,就会忽略实际主变量的值。下面的示例能正确处理空值的读取:

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 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。