6.6. 给开发者 #
本节面向想要开发 ecpg 接口的人。它描述各部分如何工作。这里的定位是让本节包含给想深入了解的人的内容,而如何使用一节应该足以回答所有常规问题。所以,在研究 ecpg 的内部之前先读这一节。如果你对它究竟如何工作不感兴趣,请跳过本节。
6.6.1. 待办列表
这个版本的预处理器有一些缺陷:
- Library functions
to_date 等不存在。不过 Postgres 自身有一些不错的转换例程。所以你大概不会想念它们。
- 结构与联合
结构和联合必须在 declare 区中定义。
- 缺失的语句
下列语句迄今尚未实现:
- exec sql allocate
- exec sql deallocate
- SQLSTATE
- 消息 'no data found'
exec sql insert select from 语句中"no data"的错误消息应该是 100。
- sqlwarn[6]
如果 SET DESCRIPTOR 语句中指定的 PRECISION 或 SCALE 值将被忽略,sqlwarn[6] 应为 'W'。
6.6.2. The Preprocessor
写入输出的前四行是 ecpg 固定添加的内容:其中两行是注释,另外两行是与库接口所必需的包含行。
随后预处理器只单遍工作,边读输入文件边写输出。通常它只是把所有内容原样回显到输出而不再细看。
遇到 EXEC SQL 语句时它会介入,并根据语句的种类改写它们。EXEC SQL 语句可以是下列这些:
- Declare sections
声明节以
exec sql begin declare section;
开始,以
exec sql end declare section;
结束。节中只允许变量声明。在这个节中声明的每个变量还会连同其相应的类型一起按名字登记到一个变量列表中。
特别是结构或联合的定义也必须列在 declare 区内。否则 ecpg 无法处理这些类型,因为它根本不知道定义。
声明也会被回显到文件中,使该变量同时成为一个普通的 C 变量。
特殊类型 VARCHAR 和 VARCHAR2 会为每个变量转换成一个命名的结构。像这样的声明:
VARCHAR var[180];
is converted into
struct varchar_var { int len; char arr[180]; } var;- 包含语句
include 语句的形式是:
exec sql include filename;
注意这不同于
#include <filename.h>
相反,指定的文件由 ecpg 自身解析。因此指定文件的内容会被包含进生成的 C 代码中。这样你就能够在 include 文件中指定 EXEC SQL 命令。
- 连接语句
connect 语句的形式是:
exec sql connect to
connection target;它创建到指定数据库的一个连接。
connection target可以用下列方式指定:- dbname[@server][:port][as
connection name][useruser name] - tcp:postgresql://server[:port][/dbname][as
connection name][useruser name] - unix:postgresql://server[:port][/dbname][as
connection name][useruser name] character variable[asconnection name][useruser name]character string[asconnection name][user]- default
- user
还有几种指定用户名的方式:
useriduserid/passworduserididentified bypassworduseridusingpassword
最后是 userid 和 password。它们各自可以是常量文本、字符变量或字符串。
- dbname[@server][:port][as
- 断开语句
disconnect 语句的形式是:
exec sql disconnect [
connection target];它关闭到指定数据库的连接。
connection target可以用下列方式指定:connection name- default
- current
- all
- 打开游标语句
open cursor 语句的形式是:
exec sql open
cursor;它被忽略,不复制到输出中。
- 提交语句
commit 语句的形式是
exec sql commit;
在输出中被翻译为
ECPGcommit(__LINE__);
- 回滚语句
rollback 语句的形式是
exec sql rollback;
and is translated on the output to
ECPGrollback(__LINE__);
- 其他语句
其他 SQL 语句是其他以
exec sql开始、以;结束的语句。中间的一切都被当作 SQL 语句并解析变量替换。当符号以冒号(
:)开头时发生变量替换。此时会在先前于声明节中声明的变量里查找具有该名字的变量,并且根据该变量用于输入还是输出,把指向变量的指针写入输出以允许函数访问。对于作为 SQL 请求一部分的每个变量,函数会另外得到十个参数:
类型(以特殊符号表示)。 指向值的指针或指向指针的指针。 变量为 char 或 varchar 时的大小。 数组中的元素个数(用于数组抓取)。 到数组中下一个元素的偏移量(用于数组抓取) 指示符变量的类型(以特殊符号表示)。 指向指示符变量值的指针或指向指示符变量指针的指针。 0。 指示符数组中的元素个数(用于数组抓取)。 到指示符数组中下一个元素的偏移量(用于数组抓取)
6.6.3. 一个完整的例子
下面是一个完整的例子,描述预处理器对文件 foo.pgc 的输出:
exec sql begin declare section;
int index;
int result;
exec sql end declare section;
...
exec sql select res into :result from mytable where index = :index;
被翻译成:
/* Processed by ecpg (2.6.0) */
/* These two include files are added by the preprocessor */
#include <ecpgtype.h>;
#include <ecpglib.h>;
/* exec sql begin declare section */
#line 1 "foo.pgc"
int index;
int result;
/* exec sql end declare section */
...
ECPGdo(__LINE__, NULL, "select res from mytable where index = ? ",
ECPGt_int,&(index),1L,1L,sizeof(int),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT,
ECPGt_int,&(result),1L,1L,sizeof(int),
ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
#line 147 "foo.pgc"
(本手册中的缩进是为了可读性而加的,并不是预处理器能做的。)
6.6.4. 库
库中最重要的函数是 ECPGdo
函数。它接受数量可变的参数。但愿我们不会碰到对 vararg 函数可接受的变量数量有限制的机器。这很容易累积到 50 个左右的参数。
参数有:
- 一个行号
这是原语句的行号,只用于错误消息。
- 一个字符串
这是要发出的 SQL 请求。该请求被输入变量修改,即那些编译时未知但要输入请求的变量。在变量应出现的位置,字符串中包含 ";"。
- 输入变量
如关于预处理器的一节所述,每个输入变量得到十个参数。
- ECPGt_EOIT
一个枚举,表示不再有输入变量。
- 输出变量
如关于预处理器的一节所述,每个输入变量得到十个参数。These variables are filled by the function.
- ECPGt_EORT
一个枚举,表示不再有变量。
所有 SQL 语句都在一个事务中执行,除非你发出提交事务。为了让这种自动事务运转起来,第一条语句或提交/回滚之后的第一条语句总是会开始一个事务。要在默认情况下禁用这个特性,请在命令行使用
-t 选项。
待完成:描述其他条目的条目。