×
Мы обрабатываем cookies, чтобы сделать наш сайт удобнее и персонализированнее для вас. Подробнее: политика использования «cookies» и «политики конфиденциальности».

Для самостоятельной настройки ознакомьтесь с инструкцией

Дополнительные настройки cookies в браузерах

Файлы cookie автоматически загружаются в ваш браузер при посещении веб-сайта. У вас есть возможность управлять этими файлами. Если Вы не согласны с использованием файлов cookies, запретите их сохранение на своём устройстве, удалите уже имеющиеся файлы cookies через настройки браузера или прекратите использование сайта.

При отключении обработки cookie наш сайт продолжит функционировать, однако будут использоваться исключительно необходимые технические файлы, без которых работа ресурса невозможна.

Инструкция по отключению cookies
Принять
Настроить
Отклонить

ДОКУМЕНТАЦИЯ

Выберите версию, форк и язык для СУБД Digital Q.DataBase, чтобы прочитать или скачать всю документацию.
Техподдержка
Документация
Диасофт
Авторские права © 2016–2025 ООО "Диасофт Экосистема"
Скачать всю документацию:

4.1.4. Асинхронная обработка команд

Функция PQexec вполне подходит для отправки команд в обычных синхронных приложениях. Однако она обладает рядом недостатков, которые могут быть существенны для некоторых пользователей:

  • PQexec ожидает завершения выполнения команды. Приложение может выполнять другие задачи (например, обслуживать пользовательский интерфейс), и в этом случае блокировка в ожидании ответа нежелательна.

  • Поскольку на время ожидания результата выполнение клиентского приложения приостанавливается, приложению сложно принять решение о необходимости отмены текущей команды. (Это можно сделать из обработчика сигналов, но не иным способом.)

  • PQexec может возвращать только одну PGresult структуру. Если переданная строка команды содержит несколько SQL команд, то все они, кроме последней, PGresult отбрасываются функцией PQexec.

  • PQexec всегда собирает весь результат команды, буферизуя его в одной PGresult. Хотя это упрощает логику обработки ошибок в приложении, такой подход может быть непрактичным для результатов, содержащих большое количество строк.

Приложения, для которых данные ограничения неприемлемы, могут использовать нижележащие функции, которые PQexec состоит из: PQsendQuery и PQgetResult. Также существуют PQsendQueryParams, PQsendPrepare, PQsendQueryPrepared, PQsendDescribePrepared, PQsendDescribePortal, PQsendClosePrepared, и PQsendClosePortal, которые можно использовать совместно с PQgetResult для дублирования функциональности PQexecParams, PQprepare, PQexecPrepared, PQdescribePrepared, PQdescribePortal PQclosePrepared, и PQclosePortal соответственно.

PQsendQuery #

Отправляет команду серверу без ожидания результатов. Возвращается 1, если команда была успешно отправлена, и 0, если нет (в этом случае используйте функцию PQerrorMessage для получения дополнительных сведений об ошибке).

int PQsendQuery(PGconn *conn, const char *command);

После успешного вызова функции PQsendQuery, вызовите функцию PQgetResult один или несколько раз для получения результатов. PQsendQuery нельзя вызвать повторно (через то же соединение) до тех пор, пока PQgetResult не будет возвращено значение NULL, что указывает на завершение выполнения команды.

В режиме конвейеризации использование данной функции не допускается.

PQsendQueryParams #

Отправляет серверу команду и отдельные параметры без ожидания получения результатов.

int PQsendQueryParams(PGconn *conn,
                      const char *command,
                      int nParams,
                      const Oid *paramTypes,
                      const char * const *paramValues,
                      const int *paramLengths,
                      const int *paramFormats,
                      int resultFormat);

Данная функция эквивалентна функции PQsendQuery за тем исключением, что параметры запроса могут быть указаны отдельно от самой строки запроса. Параметры функции обрабатываются так же, как и в функции PQexecParams. Как и функция PQexecParams, она допускает наличие только одной команды в строке запроса.

PQsendPrepare #

Отправляет запрос на создание подготовленного оператора с заданными параметры без ожидания завершения операции.

int PQsendPrepare(тип PGconn *объект conn,
                  const char *stmtName,
                  const char *query,
                  int nParams,
                  const тип Oid *paramTypes);

Данная функция является асинхронной версией функции PQprepare: она возвращает 1, если запрос был успешно отправлен, и 0 — в противном случае. После успешного вызова необходимо вызвать функцию PQgetResult для чтобы определить, был ли сервером успешно создан подготовленный оператор. Параметры данной функции обрабатываются так же, как и в функции PQprepare.

PQsendQueryPrepared #

Отправляет запрос на выполнение подготовленного оператора с заданными параметры без ожидания получения результатов.

int PQsendQueryPrepared(тип PGconn *объект conn,
                        const char *stmtName,
                        int nParams,
                        const char * const *paramValues,
                        const int *paramLengths,
                        const int *paramFormats,
                        int resultFormat);

Данная функция аналогична функции PQsendQueryParams, однако выполняемая команда определяется путём указания имени ранее подготовленного оператора вместо передачи строки запроса. Параметры функции обрабатываются так же, как и в функции PQexecPrepared.

PQsendDescribePrepared #

Отправляет запрос на получение информации об указанном подготовленного оператора без ожидания завершения.

int PQsendDescribePrepared(PGconn *conn, const char *stmtName);

Данная функция является асинхронной версией функции PQdescribePrepared: в случае успешной отправки запроса функция возвращает 1, а в противном случае — 0. После успешного вызова необходимо вызвать функцию PQgetResult для получения результатов. Параметры данной функции обрабатываются идентично параметрам PQdescribePrepared.

PQsendDescribePortal #

Отправляет запрос на получение информации об указанном портала без ожидания завершения.

int PQsendDescribePortal(PGconn *conn, const char *portalName);

Данная функция является асинхронной версией функции PQdescribePortal: в случае успешной отправки запроса функция возвращает 1, а в противном случае — 0. После успешного вызова необходимо вызвать функцию PQgetResult для получения результатов. Параметры данной функции обрабатываются идентично параметрам PQdescribePortal.

PQsendClosePrepared #

Отправляет запрос на закрытие указанного подготовленного оператора без ожидания завершения.

int PQsendClosePrepared(PGconn *conn, const char *stmtName);

Данная функция является асинхронной версией функции PQclosePrepared: в случае успешной отправки запроса функция возвращает 1, а в противном случае — 0. После успешного вызова необходимо вызвать функцию PQgetResult для получения результатов. Параметры данной функции обрабатываются идентично параметрам PQclosePrepared.

PQsendClosePortal #

Отправляет запрос на закрытие указанного портала без ожидания завершения.

int PQsendClosePortal(PGconn *conn, const char *portalName);

Данная функция является асинхронной версией функции PQclosePortal: в случае успешной отправки запроса функция возвращает 1, а в противном случае — 0. После успешного вызова необходимо вызвать функцию PQgetResult для получения результатов. Параметры данной функции обрабатываются идентично параметрам PQclosePortal.

PQgetResult #

Функция ожидает получения следующего результата предыдущего PQsendQuery, PQsendQueryParams, PQsendPrepare, PQsendQueryPrepared, PQsendDescribePrepared, PQsendDescribePortal, PQsendClosePrepared, PQsendClosePortal, PQsendPipelineSync, или PQpipelineSync вызова и возвращает его. Когда выполнение команды завершено и новых результатов не ожидается, возвращается значение NULL.

PGresult *PQgetResult(PGconn *conn);

PQgetResult Функцию необходимо вызывать многократно до тех пор, пока она не вернет значение NULL, что указывает на завершение команды. (Если функция вызывается при отсутствии активной команды, PQgetResult будет сразу возвращено значение NULL.) Каждый результат функции, отличный от значение NULL, PQgetResult следует обработать с помощью тех же самых PGresult функций доступа, которые были описаны ранее. Не забудьте освободить каждый объект результата с помощью функции PQclear после завершения работы с ним. Обратите внимание, что функция PQgetResult блокируется только в том случае, если команда активна, а необходимые данные ответа еще не были прочитаны функцией PQconsumeInput .

В режиме конвейерной обработки PQgetResult управление возвращается в обычном режиме, если не возникнет ошибка; для любого последующего запроса, отправленного после того, который вызвал ошибку, вплоть до следующей точки синхронизации (не включая её), специальный результат типа PGRES_PIPELINE_ABORTED будет будет возвращен, а следом за ним — значение NULL. При достижении точки синхронизации конвейера будет возвращен результат типа PGRES_PIPELINE_SYNC will be returned. Результат следующего после точки синхронизации запроса следует незамедлительно (то есть после точки синхронизации значение NULL не возвращается).

Примечание

Даже если PQresultStatus указывает на неустранимую ошибку, PQgetResult функция должна вызываться до тех пор, пока она не вернет значение NULL, чтобы обеспечить libpq для полную обработку информации об ошибке.

Использование функций PQsendQuery и PQgetResult позволяет решить одну из PQexecпроблем: если командная строка содержит несколько SQL команд, результаты выполнения этих команд можно получить по отдельности. (Кстати, это позволяет реализовать простую форму совмещенной обработки: клиент может обрабатывать результаты одной команды, в то время как сервер все еще работает над последующими запросами в той же командной строке.)

Еще одна часто востребованная функциональность, которую можно реализовать с помощью PQsendQuery и PQgetResult — это получение результатов больших запросов с ограничением количества строк, запрашиваемых за один раз. Данный вопрос рассматривается в Раздел 4.1.6.

Самостоятельный вызов функции PQgetResult все равно приведет к блокировке клиента до тех пор, пока сервером не будет завершена следующая SQL команда. Этого можно избежать за счет надлежащего использования еще двух функций:

PQconsumeInput #

Если от сервера поступили входные данные, они считываются.

int PQconsumeInput(PGconn *conn);

PQconsumeInput обычно возвращает 1, что указывает на «ошибок нет», но возвращает 0, если возникла какая-либо ошибка (в этом случае следует обратиться к PQerrorMessage могут быть ). Обратите внимание, что результат не указывает на то, были ли фактически получены какие-либо входные данные. После вызова функции PQconsumeInput приложение может проверить PQisBusy и/или функцию PQnotifies , чтобы определить, изменилось ли их состояние.

PQconsumeInput можно вызывать даже в том случае, если приложение еще не готово к обработке результата или уведомления . Данная функция прочитает доступные данные и сохранит их в буфере, тем самым устраняя select() признак готовности к чтению. Таким образом, приложение может использовать функцию PQconsumeInput для немедленного сброса select() состояния готовности, а затем проверить результаты в свободном режиме.

PQisBusy #

Данная функция возвращает 1, если команда занята, то есть, PQgetResult если выполнение приведет к блокировке в ожидании ввода. Возвращаемое значение 0 указывает на то, что функция PQgetResult могут быть может быть вызвана с гарантией отсутствия блокировки.

int PQisBusy(тип PGconn *объект conn);

PQisBusy не выполняет попыток самостоятельного чтения данных с сервера; следовательно, функция PQconsumeInput должна быть вызвана первой, иначе состояние занятости никогда не завершится.

В типичном приложении, использующем данные функции, предусматривается основной цикл, в котором используется select() или poll() для ожидания всех условий, на которые необходимо реагировать. Одним из таких условий является наличие доступных входных данных от сервера, что с точки зрения select() означает наличие готовых к чтению данных в файловом дескрипторе, который идентифицирует функция PQsocket. При обнаружении в основном цикле готовности входных данных должна вызываться функция PQconsumeInput для чтения входных данных. После этого она может вызвать PQisBusy, а вслед за ней — функция PQgetResult в том случае, если функция PQisBusy возвращает false (0). Также может быть вызвана функция PQnotifies для обнаружения NOTIFY сообщения (см. Раздел 4.1.9).

Клиент, использующий PQsendQuery/PQgetResult также может попытаться отменить команду, которая все еще обрабатывается сервером; см. Раздел 4.1.7. Но независимо от возвращаемого значения функции PQcancelBlocking, приложение должно продолжить обычную последовательность чтения результатов, используя функцию PQgetResult. Успешная отмена просто приведет к тому, что выполнение команды завершится раньше, чем это произошло бы в противном случае.

Используя описанные выше функции, можно избежать блокировки приложения при ожидании данных от сервера базы данных. Однако все же существует вероятность того, что приложение будет заблокировано в ожидании отправки данных на сервер. Это происходит относительно редко, но возможно при передаче очень длинных SQL-команд или значений данных. (Это гораздо более вероятно, если приложение передает данные через COPY IN, однако.) Чтобы исключить такую возможность и обеспечить полностью неблокирующую работу с базой данных, можно использовать следующие дополнительные функции.

PQsetnonblocking #

Устанавливает для соединения неблокирующий статус.

int PQsetnonblocking(PGconn *conn, int arg);

Переводит соединение в неблокирующий режим, если arg имеет значение 1, или в блокирующий режим, если значение arg равно 0. Функция возвращает 0 в случае успеха и -1 при возникновении ошибки.

В неблокирующем состоянии успешные вызовы функций PQsendQuery, PQputline, PQputnbytes, PQputCopyData, и PQendcopy не будут приводить к блокировке; вносимые ими изменения сохраняются в локальном выходном буфере до момента их отправки. В случае неудачного вызова возвращается ошибка, после чего попытку необходимо повторить.

Обратите внимание, что функция PQexec не учитывает неблокирующий режим; при вызове она в любом случае будет работать в блокирующем режиме.

PQisnonblocking #

Возвращает статус блокировки для соединения с базой данных.

int PQisnonblocking(const PGconn *conn);

Возвращает 1, если для соединения установлен неблокирующий режим, и 0, если режим соединения — блокирующий.

PQflush #

Выполняет попытку сброса любых поставленных в очередь выходных данных на сервер. Функция возвращает 0 в случае успеха (или если очередь отправки пуста), -1 в случае возникновения ошибки или 1, если пока не удалось отправить все данные из очереди отправки (данный случай возможен только в том случае, если соединение является неблокирующим).

int PQflush(PGconn *conn);

После отправки любой команды или данных через неблокирующее соединение вызовите функцию PQflush. Если она возвращает 1, дождитесь готовности сокета к чтению или записи. Если сокет становится готовым к записи, вызовите функцию PQflush снова. Если сокет становится готовым к чтению, вызовите функцию PQconsumeInput , а затем вызовите функцию PQflush снова. Повторяйте эти действия, пока функция PQflush не вернет 0. (Необходимо проверить готовность к чтению и очистить буфер ввода с помощью функции PQconsumeInput , поскольку сервер может быть заблокирован при попытке отправить данные, например сообщения NOTICE, и не будет принимать данные от клиента, пока тот не считает данные от сервера.) Как только функция PQflush вернет 0, следует дождаться готовности сокета к чтению, после чего считать ответ согласно приведенному выше описанию.

Наверх
свяжитесь
с нами
контакты
Для прямой связи с нами вы можете использовать контакты ниже, либо оставить заявку через форму обратной связи, и мы обязательно свяжемся с вами

*поля обязательные к заполнению