37.17. Внутреннее устройство
В этом разделе рассказывается, как препроцессор ECPG устроен внутри. Эта информация может оказаться полезной для пользователей, желающих понять, как использовать ECPG.
Первые четыре строки, которые ecpg
записывает в вывод, фиксированы. Первые две строки содержат комментарии, а следующие две директивы включения, подключающие интерфейс к библиотеке. Затем препроцессор прочитывает файл и продолжает запись в вывод. Обычно он просто печатает всё в устройство вывода.
Встречая команду EXEC SQL
, он вмешивается и изменяет её. Данная команда начинается со слов EXEC SQL
и заканчивается знаком ;
. Всё между ними воспринимается как оператор SQL и разбирается для подстановки переменных.
Подстановка переменных имеет место, когда символ начинается с двоеточия (:
). ECPG будет искать переменную с таким именем среди переменных, ранее объявленных в секции EXEC SQL DECLARE
.
Самая важная функция в библиотеке — ECPGdo
, которая осуществляет выполнение большинства команд. Она принимает переменное число аргументов (это число легко может достигать 50, и мы надеемся, что это не приведёт к проблемам ни на какой платформе).
Ей передаются следующие аргументы:
- Номер строки
Номер исходной строки; используется только в сообщениях об ошибках.
- Строка
Команда SQL, которая должна быть выполнена. На её содержимое влияют входные переменные, то есть переменные, добавленные в команду, но неизвестные во время компиляции. Места, в которые должны вставляться переменные, обозначаются знаками
?
.- Входные переменные
Для каждой входной переменной формируются десять аргументов. (См. ниже.)
ECPGt_EOIT
Перечисление (
enum
), показывающее, что больше входных переменных нет.- Выходные переменные
Для каждой входной переменной формируются десять аргументов. (См. ниже.) Эти переменные заполняются данной функцией.
ECPGt_EORT
Перечисление (
enum
), показывающее, что больше выходных переменных нет.
Для каждой переменной, включённой в команду SQL, эта функция принимает десять аргументов:
Тип в виде специального символа.
Указатель на значение или указатель на указатель.
Размер переменной, если она имеет тип
char
илиvarchar
.Число элементов в массиве (при выборке данных в массив).
Смещение следующего элемента в массиве (при выборке данных в массив).
Тип переменной-индикатора в виде специального символа.
Указатель на переменную-индикатор.
0
Число элементов в массиве индикаторов (при выборке данных в массив).
Смещение следующего элемента в массиве индикаторов (при выборке данных в массив).
Заметьте, что не все команды SQL обрабатываются таким образом. Например, команда открытия курсора вида:
EXEC SQL OPEN курсор
;
не копируется в вывод. Вместо этого в позиции команды 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;
преобразуется в:
/* 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"
(Отступы здесь добавлены для читаемости, препроцессор их не вставляет.)
37.17. Internals
This section explains how ECPG works internally. This information can occasionally be useful to help users understand how to use ECPG.
The first four lines written by ecpg
to the output are fixed lines. Two are comments and two are include lines necessary to interface to the library. Then the preprocessor reads through the file and writes output. Normally it just echoes everything to the output.
When it sees an EXEC SQL
statement, it intervenes and changes it. The command starts with EXEC SQL
and ends with ;
. Everything in between is treated as an SQL statement and parsed for variable substitution.
Variable substitution occurs when a symbol starts with a colon (:
). The variable with that name is looked up among the variables that were previously declared within a EXEC SQL DECLARE
section.
The most important function in the library is ECPGdo
, which takes care of executing most commands. It takes a variable number of arguments. This can easily add up to 50 or so arguments, and we hope this will not be a problem on any platform.
The arguments are:
- A line number
This is the line number of the original line; used in error messages only.
- A string
This is the SQL command that is to be issued. It is modified by the input variables, i.e., the variables that where not known at compile time but are to be entered in the command. Where the variables should go the string contains
?
.- Input variables
Every input variable causes ten arguments to be created. (See below.)
ECPGt_EOIT
An
enum
telling that there are no more input variables.- Output variables
Every output variable causes ten arguments to be created. (See below.) These variables are filled by the function.
ECPGt_EORT
An
enum
telling that there are no more variables.
For every variable that is part of the SQL command, the function gets ten arguments:
The type as a special symbol.
A pointer to the value or a pointer to the pointer.
The size of the variable if it is a
char
orvarchar
.The number of elements in the array (for array fetches).
The offset to the next element in the array (for array fetches).
The type of the indicator variable as a special symbol.
A pointer to the indicator variable.
0
The number of elements in the indicator array (for array fetches).
The offset to the next element in the indicator array (for array fetches).
Note that not all SQL commands are treated in this way. For instance, an open cursor statement like:
EXEC SQL OPEN cursor
;
is not copied to the output. Instead, the cursor's DECLARE
command is used at the position of the OPEN
command because it indeed opens the cursor.
Here is a complete example describing the output of the preprocessor of a file foo.pgc
(details might change with each particular version of the preprocessor):
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;
is translated into:
/* 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"
(The indentation here is added for readability and not something the preprocessor does.)