Асинхронная обработка запросов
Средства интерфейса нижнего уровня обеспечивают возможность
асинхронной обработки запросов СУБД ЛИНТЕР.
Для этого при обращении к СУБД необходимо установить бит Q_ASYNC
(признак асинхронного выполнения запроса) в поле
PrzExe
контрольного блока
обработки запроса
CBL
и, если необходимо, адрес процедуры завершения асинхронной обработки,
которой СУБД передаст результаты выполнения
асинхронного запроса. После отправки асинхронного запроса к СУБД управление сразу
возвращается клиентскому приложению, которое может продолжать свою
работу.
После выполнения ядром СУБД асинхронного запроса (а это, в зависимости от
сложности запроса, может быть длительный процесс) работа клиентского
приложения прерывается,
управление передается пользовательской процедуре завершения обработки
асинхронного запроса (если она была задана) и после ее завершения
вновь возвращается клиентскому приложению.
Пользовательская процедура завершения асинхронной обработки должна
иметь следующий прототип:
void Proc_Name(TCBL *CBL, void*RowBuf, void *VarBuf);
В параметрах
CBL
(адрес контрольного блока запроса),
RowBuf
(адрес буфера для приема выборки данных)
и
VarBuf
(адрес буфера для приема
маски NULL-значений
выборки данных) будут переданы результаты выполнения асинхронного
запроса.
Если какой-либо из параметров (это может быть либо
VarBuf
, либо
RowBuf
) не является выходным параметром асинхронного запроса,
вместо его адреса рекомендуется передать NULL-значение.
Внутри пользовательской процедуры завершения асинхронной обработки можно также использовать асинхронные команды, однако нельзя использовать синхронные обращения к СУБД.
В многонитевых (многопотоковых) приложениях процедура асинхронной
обработки выполняется в отдельной, специально созданной для этих
целей, нити (потоке).
В некоторых случаях для процедур асинхронной обработки может
потребоваться увеличить размер стека. Для этого до первого вызова
функции inter
(или любой функции интерфейса) должна быть вызвана функция
inter_control
, в которой код операции
IC_code
должен быть установлен в
ICR_SET_STACK_SIZE
, а длина буфера данных
LenOpBuf
должна содержать нужный размер стека.
Минимальный размер стека должен составлять MAX_CLIENT_BUFSIZE + 8192 байт. В
случае необходимости это значение должно быть увеличено на размер
данных в стеке
процедуры асинхронной обработки запроса.
Примечания
-
Процедура асинхронной обработки для многонитевых (многопотоковых) приложений выполняется в специально созданной для этого нити (потоке). Интерфейс для ОС Windows всегда многонитевый. ОС Linux или UNIX может использовать как многонитевый (многопотоковый) интерфейс, так и однопотоковый. В последнем случае процедура асинхронной обработки выполняется из обработчика сигнала.
-
Для удобства пользователей в файле
inter.h
, входящем в состав дистрибутива СУБД ЛИНТЕР, определен прототип функции USR_PROC:typedef void (*USR_PROC)(TCBL *, HPVOID, HPVOID);
Клиентское приложение может синхронизировать свое выполнение с любым
асинхронным запросом. Для этого необходимо вызвать функцию
inter_wait_single:
L_BOOL inter_wait_single(TCBL *CBL, LONGINT Timeout);
где:
-
CBL
– контрольный блок, использованный для подачи асинхронного запроса (для различных асинхронных запросов должны использоваться разныеCBL
); -
Timeout
– предельное время ожидания завершения асинхронного запроса. Зарезервировано для будущего использования.
Если к моменту вызова функции inter_wait_single выполнение запроса
(совместно с пользовательской функцией завершения обработки
асинхронного запроса) уже завершилось,
inter_wait_single вернет управление клиентскому приложению. По факту выполнения
асинхронного запроса в поле
PrzExe
контрольного блока выставляется бит Q_ASYNCDONE.
Функция возвращает:
-
L_TTRUE, если вызов был с правильным CBL (т.е. с тем CBL, с которым выполнялся соответствующий ей вызов inter);
-
L_TFALSE, если вызов был с ошибочным CBL.
Примечание
Если функция
inter
использует асинхронную обработку, то соответствующая ей функция
inter_wait_single
должна ссылаться на тот же
самый контрольный блок, что и функция
inter
.
Примеры формирования асинхронного запроса
-
#include < string.h > #include < stdlib.h > #include "inter.h" void LinterASYNC_OPEN(TCBL *pCBL, L_CHAR *Name_Pass, L_CHAR *Node, L_WORD Prior, L_LONG PrzExe, USR_PROC func) { memcpy(pCBL- >Command, "OPEN", 4); if (strlen(Node) > MAX_NODE_LEN) { pCBL- >CodErr=SQLLONGID; func(pCBL, NULL, NULL); return; } memset(pCBL- >Node, 0, MAX_NODE_LEN); memcpy(pCBL- >Node, Node, strlen(Node)); pCBL- >PrzExe=PrzExe | Q_ASYNC; pCBL- >Prior=Prior; inter(pCBL, Name_Pass, NULL, (void *) func, NULL); }
-
#include < string.h > #include < stdlib.h > #include "inter.h" void LinterASYNC_SLCT(TCBL *pCBL, L_LONG PrzExe, L_CHAR *Statement, void *RowBuf, L_WORD RowBufLen, void *VarBuf, USR_PROC func) { memcpy(pCBL- >Command, "SLCT", 4); pCBL- >PrzExe=PrzExe | Q_ASYNC; pCBL- >LnBufRow=RowBufLen; inter (pCBL, VarBuf, Statement, (void *) func, RowBuf); }
Примеры асинхронной обработки запроса
-
#include < stdio.h > #include < stdlib.h > #include < string.h > #include "inter.h" #include "exlib.h" #ifndef WINCE int main() #else int aexopen() #endif { TCBL CBLconnect; L_CHAR Name_Pass[] = "SYSTEM/MANAGER8"; L_CHAR Node[] = " "; L_WORD Priority = 0; L_LONG PrzExe = M_EXCLUSIVE | Q_ENCODE | M_BINARY; memset(&CBLconnect,0,sizeof(TCBL)); LinterASYNC_OPEN(&CBLconnect, Name_Pass, Node, Priority, PrzExe, WorkError); printf("Connecting to RDBMS Linter ... "); fflush(stdout); /* ... */ inter_wait_single(&CBLconnect, -1); printf("Ok\n"); printf("End Example\n"); return 0; }
-
#include < stdio.h > #include < stdlib.h > #include < string.h > #include "inter.h" #include "exlib.h" #ifndef WINCE int main() #else int aexslct() #endif { struct TRowBuf { L_CHAR Name[20]; L_CHAR FirstName[15]; L_CHAR Sex; }; typedef struct TRowBuf TRowBuf; TCBL CBLconnect; L_CHAR Name_Pass[] = "SYSTEM/MANAGER8"; L_CHAR Node[] = " "; L_WORD Priority = 0; L_LONG PrzExe = M_EXCLUSIVE | Q_ENCODE | M_BINARY; L_LONG Err; L_CHAR Query[] = "select NAME,FIRSTNAM, SEX from PERSON;"; TRowBuf RowBuf; memset(&CBLconnect,0,sizeof(TCBL)); Err=LinterOPEN(&CBLconnect, Name_Pass, Node, Priority, PrzExe); if (Err != NORMAL) PrintError(&CBLconnect); printf("Connect to RDBMS Linter\n"); LinterASYNC_SLCT(&CBLconnect, PrzExe, Query, &RowBuf, sizeof(TRowBuf), NULL, WorkError); printf("Selecting ... "); fflush(stdout); /* ... */ inter_wait_single(&CBLconnect, -1); printf("Ok\n"); printf("First Selected Row:\n"); printf("%.20s %.15s %c\n", RowBuf.Name, RowBuf.FirstName, RowBuf.Sex); printf("End Example\n"); return 0; }