34.6. Извлечение порциями информации, связанной с результатом запроса #
Обычно libpq собирает весь результат выполнения SQL-команды и возвращает его приложению в виде единственной структуры PGresult. Это может оказаться неприемлемым для команд, которые возвращают большое число строк. В таких случаях приложение может воспользоваться функциями PQsendQuery и PQgetResult в однострочном режиме или порционном режиме. В этих режимах результирующие строки передаются приложению по мере того, как они принимаются от сервера, — по одной за раз в однострочном и по несколько в порционном режиме.
Для того чтобы войти в один из этих режимов, вызовите PQsetSingleRowMode или PQsetChunkedRowsMode сразу же после успешного вызова функции PQsendQuery (или родственной функции). Выбор этого режима действителен только для запроса, исполняемого в данный момент. Затем повторно вызывайте функцию PQgetResult до тех пор, пока она не возвратит null, как описано в Раздел 34.4. Если запрос возвращает какое-то число строк, то они возвращаются в виде одного или нескольких объектов PGresult, которые выглядят, как обычные выборки, за исключением того, что их код статуса будет PGRES_SINGLE_TUPLE в однострочном режиме или PGRES_TUPLES_CHUNK в порционном режиме вместо PGRES_TUPLES_OK. В каждом объекте PGRES_SINGLE_TUPLE будет выведена только одна результирующая строка, в то время как объект PGRES_TUPLES_CHUNK содержит хотя бы одну строку, но не больше указанного числа строк на одну порцию. После последней строки (или сразу же, если запрос не возвращает ни одной строки) будет возвращён объект, не содержащий ни одной строки и имеющий статус PGRES_TUPLES_OK; это сигнал о том, что строк больше не будет. (Но обратите внимание, что всё же необходимо продолжать вызывать функцию PQgetResult, пока она не возвратит null.) Все эти объекты PGresult будут содержать те же самые описательные данные (имена столбцов, типы и т. д.), которые имел бы обычный объект PGresult. Память, занимаемую каждым объектом, нужно освобождать с помощью PQclear, как обычно.
При использовании конвейерного режима необходимо активировать однострочный или порционный режим для каждого запроса в конвейере, прежде чем получать результаты для этого запроса с помощью PQgetResult. См. Раздел 34.5 для получения дополнительной информации.
PQsetSingleRowMode#Выбирает однострочный режим для текущего выполняющегося запроса.
int PQsetSingleRowMode(PGconn *conn);
Эту функцию можно вызывать только непосредственно после функции
PQsendQueryили одной из её родственных функций, до выполнения любой другой операции через это подключение, такой, какPQconsumeInputилиPQgetResult. Если вызвать её в подходящий момент, функция активирует однострочный режим для текущего запроса и возвращает 1. В противном случае режим остаётся прежним, а функция возвращает 0. Режим в любом случае сбрасывается по завершении текущего запроса.PQsetChunkedRowsMode#Выбирает порционный режим для текущего выполняющегося запроса.
int PQsetChunkedRowsMode(PGconn *conn, int chunkSize);
Эта функция похожа на
PQsetSingleRowMode, но вместо того, чтобы получать на каждыйPGresultтолько одну строку за раз, выводит порции строк, максимальное количество которых указано вchunkSize. Данную функцию можно вызывать только сразу после функцииPQsendQueryили одной из её родственных функций, до выполнения любой другой операции через это подключение, такой, какPQconsumeInputилиPQgetResult. Если вызвать её в подходящий момент, функция активирует порционный режим для текущего запроса и возвращает 1. В противном случае режим остаётся прежним, а функция возвращает 0. Режим в любом случае сбрасывается по завершении текущего запроса.
Внимание
В процессе обработки запроса сервер может возвратить некоторое количество строк, а затем столкнуться с ошибкой, вынуждающей его аварийно завершить запрос. Обычно libpq отбрасывает такие строки и сообщает только об ошибке. Но в однострочном или порционном режиме эти строки уже будут возвращены приложению. Следовательно, приложение увидит ряд объектов PGresult, имеющих статус PGRES_SINGLE_TUPLE или PGRES_TUPLES_CHUNK, за которыми последует объект со статусом PGRES_FATAL_ERROR. Для обеспечения надлежащего поведения транзакций приложение должно быть спроектировано таким образом, чтобы отбрасывать или отменять все операции, проведённые с уже обработанными строками, если запрос в конечном итоге завершается сбоем.
34.6. Retrieving Query Results in Chunks #
Ordinarily, libpq collects an SQL command's entire result and returns it to the application as a single PGresult. This can be unworkable for commands that return a large number of rows. For such cases, applications can use PQsendQuery and PQgetResult in single-row mode or chunked mode. In these modes, result row(s) are returned to the application as they are received from the server, one at a time for single-row mode or in groups for chunked mode.
To enter one of these modes, call PQsetSingleRowMode or PQsetChunkedRowsMode immediately after a successful call of PQsendQuery (or a sibling function). This mode selection is effective only for the currently executing query. Then call PQgetResult repeatedly, until it returns null, as documented in Section 34.4. If the query returns any rows, they are returned as one or more PGresult objects, which look like normal query results except for having status code PGRES_SINGLE_TUPLE for single-row mode or PGRES_TUPLES_CHUNK for chunked mode, instead of PGRES_TUPLES_OK. There is exactly one result row in each PGRES_SINGLE_TUPLE object, while a PGRES_TUPLES_CHUNK object contains at least one row but not more than the specified number of rows per chunk. After the last row, or immediately if the query returns zero rows, a zero-row object with status PGRES_TUPLES_OK is returned; this is the signal that no more rows will arrive. (But note that it is still necessary to continue calling PQgetResult until it returns null.) All of these PGresult objects will contain the same row description data (column names, types, etc.) that an ordinary PGresult object for the query would have. Each object should be freed with PQclear as usual.
When using pipeline mode, single-row or chunked mode needs to be activated for each query in the pipeline before retrieving results for that query with PQgetResult. See Section 34.5 for more information.
PQsetSingleRowMode#Select single-row mode for the currently-executing query.
int PQsetSingleRowMode(PGconn *conn);
This function can only be called immediately after
PQsendQueryor one of its sibling functions, before any other operation on the connection such asPQconsumeInputorPQgetResult. If called at the correct time, the function activates single-row mode for the current query and returns 1. Otherwise the mode stays unchanged and the function returns 0. In any case, the mode reverts to normal after completion of the current query.PQsetChunkedRowsMode#Select chunked mode for the currently-executing query.
int PQsetChunkedRowsMode(PGconn *conn, int chunkSize);
This function is similar to
PQsetSingleRowMode, except that it specifies retrieval of up tochunkSizerows perPGresult, not necessarily just one row. This function can only be called immediately afterPQsendQueryor one of its sibling functions, before any other operation on the connection such asPQconsumeInputorPQgetResult. If called at the correct time, the function activates chunked mode for the current query and returns 1. Otherwise the mode stays unchanged and the function returns 0. In any case, the mode reverts to normal after completion of the current query.
Caution
While processing a query, the server may return some rows and then encounter an error, causing the query to be aborted. Ordinarily, libpq discards any such rows and reports only the error. But in single-row or chunked mode, some rows may have already been returned to the application. Hence, the application will see some PGRES_SINGLE_TUPLE or PGRES_TUPLES_CHUNK PGresult objects followed by a PGRES_FATAL_ERROR object. For proper transactional behavior, the application must be designed to discard or undo whatever has been done with the previously-processed rows, if the query ultimately fails.