Асинхронная обработка запросов

Средства интерфейса нижнего уровня обеспечивают возможность асинхронной обработки запросов СУБД ЛИНТЕР. Для этого при обращении к СУБД необходимо установить бит 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 байт. В случае необходимости это значение должно быть увеличено на размер данных в стеке процедуры асинхронной обработки запроса.

Примечания

  1. Процедура асинхронной обработки для многонитевых (многопотоковых) приложений выполняется в специально созданной для этого нити (потоке). Интерфейс для ОС Windows всегда многонитевый. ОС Linux или UNIX может использовать как многонитевый (многопотоковый) интерфейс, так и однопотоковый. В последнем случае процедура асинхронной обработки выполняется из обработчика сигнала.

  2. Для удобства пользователей в файле 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.

Примеры формирования асинхронного запроса

  1. #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);
       }
  2. #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);
       }

Примеры асинхронной обработки запроса

  1. #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;
       }
  2. #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;
       }