33.16. 内部
这一节解释ECPG在内部是如何运转的。 这些信息有时候可以帮助用户理解如何使用ECPG。
ecpg
写到输出里的头四行是固定的行。两行是注释, 另外两行是与库接口的必要行。 然后预处理器读取文件并且写输出流。 通常它只是把所有东西都回显到输出中去。
如果它看到一个EXEC SQL
语句, 它就变换并且修改它。命令以EXEC SQL
开头,以;
结尾。 所有在中间的东西都被当 作一个SQL语句并且进行变量代换的解析。
如果一个符号以一个冒号(:
)开头,则发生变量代换。 在EXEC SQL DECLARE
段里预先声明的变量中找出该名字的变量。
库里面最重要的函数是ECPGdo
,它负责执行大多数命令。 它接受变量的参数个数。 这些参数的个数可能很容易达到50个或者更多, 我们希望在任何平台上这都不是问题。
参数是:
行号
这是原始行的行号;只是在错误信息中使用。
字符串
这是要发出的SQL命令。 它被输入变量修改,也就是说,在编译时未知的, 但是需要输入到命令中的变量。 此处变量应该包含字符串?
。
输入变量
每个输入变量都导致十个参数的生成。(见下文)
ECPGt_EOIT
一个enum
告诉没有更多输入变量了。
输出变量
每个输出变量导致十个参数的创建。(见下文) 这些变量被这些函数填充。
ECPGt_EORT
一个指出没有更多变量的enum
。
对于每个属于SQL命令一部分的变量, 函数可以得到十个参数:
作为特殊符号的类型。
一个指向其数值的指针,或者一个指向指针的指针。
如果变量大小是
char
或者varchar
。数组中元素的个数(用于抓取数组)。
指向数组中下一个元素的偏移量(用于抓取数组)。
作为一种特殊符号的指示器变量的类型。
一个指向指示器变量的指针。
0
指示器数组中的元素个数(用于抓取数组)。
指向指示器数组的下一个元素的偏移量(用于抓取数组)。
请注意,不是所有SQL命令都这么被对待。 比如,一个像下面这样的打开游标的语句。
EXEC SQL OPEN _cursor_;
不会被拷贝到输出中。 而是在OPEN
命令的位置使用游标的DECLARE
命令, 因为它同样也打开游标。
下面是一个完整的例子,描述了文件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;
被翻译成:
/* 通过ecpg (2.6.0)处理,通过预处理器添加2个include文件*/
#include <ecpgtype.h>;
#include <ecpglib.h>;
/* exec sql开始声明段 */
#line 1 "foo.pgc"
int index;
int result;
/* exec sql结束声明段 */
...
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"
(这里的凹进是为了增强可读性加的,可不是预处理器能干的事情。)