32.10. Функции, связанные с командой COPY#
32.10. Функции, связанные с командой COPY
Команда COPY
в Tantor SE имеет опции для чтения из или записи в сетевое соединение, используемое libpq.
Функции, описанные в этом разделе, позволяют приложениям использовать эту возможность, предоставляя или потребляя скопированные данные.
Весь процесс заключается в том, что приложение сначала выполняет SQL-команду COPY
с помощью функции PQexec
или одной из эквивалентных функций. Ответ на это (если в команде нет ошибок) будет объект PGresult
с кодом состояния PGRES_COPY_OUT
или PGRES_COPY_IN
(в зависимости от указанного направления копирования). Затем приложение должно использовать функции этого раздела для приема или передачи строк данных. По завершении передачи данных возвращается другой объект PGresult
, указывающий на успешность или неудачу передачи. Его статус будет PGRES_COMMAND_OK
в случае успеха или PGRES_FATAL_ERROR
, если возникла проблема. В этот момент можно выполнять дополнительные SQL-команды с помощью функции PQexec
. (Невозможно выполнять другие SQL-команды с использованием того же соединения во время выполнения операции COPY
).
Если команда COPY
выполняется с помощью
PQexec
в строке, которая может содержать дополнительные
команды, приложение должно продолжать получать результаты с помощью
PQgetResult
после завершения последовательности
COPY
. Только когда PQgetResult
возвращает
NULL
, можно быть уверенным, что строка команды PQexec
завершена и безопасно выполнять дополнительные команды.
Функции этого раздела должны выполняться только после получения
статуса результата PGRES_COPY_OUT
или
PGRES_COPY_IN
из PQexec
или
PQgetResult
.
Объект PGresult
, имеющий одно из этих значений статуса, содержит дополнительные данные о операции COPY
, которая начинается. Эти дополнительные данные доступны с помощью функций, которые также используются в связи с результатами запросов:
PQnfields
Возвращает количество столбцов (полей), которые будут скопированы.
PQbinaryTuples
0 указывает на то, что общий формат копирования является текстовым (строки разделены символами перехода строки, столбцы разделены разделительными символами и т. д.). 1 указывает на то, что общий формат копирования является двоичным. См. COPY для получения дополнительной информации.
PQfformat
Возвращает код формата (0 для текста, 1 для двоичного) для каждого столбца операции копирования. Коды формата для каждого столбца всегда будут равны нулю, когда общий формат копирования является текстовым, но двоичный формат может поддерживать как текстовые, так и двоичные столбцы. (Однако, на данный момент, в текущей реализации
COPY
в двоичной копии присутствуют только двоичные столбцы; поэтому коды формата для каждого столбца всегда соответствуют общему формату).
32.10.1. Функции для отправки данных COPY
Эти функции используются для отправки данных во время COPY FROM STDIN
. Они завершатся неудачей, если вызываются, когда соединение не находится в состоянии COPY_IN
.
PQputCopyData
Отправляет данные на сервер во время состояния
COPY_IN
.int PQputCopyData(PGconn *conn, const char *buffer, int nbytes);
Передает данные
COPY
в указанныйbuffer
длинойnbytes
на сервер. Результат равен 1, если данные были поставлены в очередь, ноль, если они не были поставлены в очередь из-за заполненных буферов (это происходит только в неблокирующем режиме), или -1, если произошла ошибка. (ИспользуйтеPQerrorMessage
для получения подробностей, если возвращаемое значение равно -1. Если значение равно нулю, ожидайте готовности к записи и повторите попытку).Приложение может разделить потоковые данные
COPY
на буферные загрузки любого удобного размера. Границы загрузки буфера не имеют семантического значения при отправке. Содержимое потоковых данных должно соответствовать ожидаемому формату данных командыCOPY
; см. COPY для получения подробной информации.PQputCopyEnd
Отправляет серверу индикацию конца данных во время состояния
COPY_IN
.int PQputCopyEnd(PGconn *conn, const char *errormsg);
Сообщение об ошибке
COPY_IN
успешно завершается, еслиerrormsg
равноNULL
. Еслиerrormsg
не равноNULL
, тоCOPY
принудительно завершается с ошибкой, где строка, на которую указываетerrormsg
, используется в качестве сообщения об ошибке. (Однако не следует предполагать, что это точное сообщение об ошибке вернется с сервера, поскольку сервер может уже завершитьCOPY
по своим собственным причинам).Результат равен 1, если сообщение о завершении было отправлено; или в неблокирующем режиме это может указывать только на то, что сообщение о завершении было успешно поставлено в очередь. (В неблокирующем режиме, чтобы быть уверенным, что данные были отправлены, следует дождаться готовности к записи и вызвать
PQflush
, повторяя это до тех пор, пока он не вернет ноль). Ноль указывает на то, что функция не смогла поставить сообщение о завершении в очередь из-за полных буферов; это произойдет только в неблокирующем режиме. (В этом случае дождитесь готовности к записи и повторите вызовPQputCopyEnd
). Если произошла серьезная ошибка, возвращается -1; вы можете использоватьPQerrorMessage
для получения подробной информации.После успешного вызова
PQputCopyEnd
, вызовитеPQgetResult
, чтобы получить окончательный статус выполнения командыCOPY
. Можно дождаться доступности этого результата обычным способом. Затем вернитесь к нормальной работе.
32.10.2. Функции для получения данных COPY
Эти функции используются для получения данных во время COPY TO
STDOUT
. Они завершатся неудачей, если вызываются, когда соединение не находится в состоянии COPY_OUT
.
PQgetCopyData
Получает данные от сервера во время состояния
COPY_OUT
.int PQgetCopyData(PGconn *conn, char **buffer, int async);
Попытки получить еще одну строку данных от сервера во время
COPY
. Данные всегда возвращаются по одной строке; если доступна только частичная строка, она не возвращается. Успешное получение строки данных включает выделение блока памяти для хранения данных. Параметрbuffer
должен быть не-NULL
.*buffer
устанавливается для указания на выделенную память или наNULL
в случаях, когда буфер не возвращается. Результат, отличный отNULL
, должен быть освобожден с помощьюPQfreemem
, когда он больше не нужен.Когда строка успешно возвращается, возвращаемое значение - это количество байтов данных в строке (оно всегда будет больше нуля). Возвращаемая строка всегда завершается нулевым символом, хотя это, вероятно, полезно только для текстовой команды
COPY
. Результат равный нулю указывает на то, чтоCOPY
все еще выполняется, но строка еще не доступна (это возможно только при установленном значенииasync
в true). Результат -1 указывает на то, чтоCOPY
завершен. Результат -2 указывает на то, что произошла ошибка (см.PQerrorMessage
для получения причины).Когда параметр
async
равен true (не нулю),PQgetCopyData
не будет блокироваться в ожидании ввода; он вернет ноль, еслиCOPY
все еще выполняется, но нет доступных полных строк. (В этом случае дождитесь готовности к чтению и затем вызовитеPQconsumeInput
перед повторным вызовомPQgetCopyData
). Когда параметрasync
равен false (нулю),PQgetCopyData
будет блокироваться до тех пор, пока данные не станут доступными или операция не завершится.После того, как
PQgetCopyData
возвращает -1, вызовитеPQgetResult
для получения окончательного статуса выполнения командыCOPY
. Можно дождаться доступности этого результата обычным способом. Затем вернитесь к нормальной работе.
32.10.3. Устаревшие функции для COPY
Эти функции представляют более старые методы обработки COPY
.
Хотя они все еще работают, они устарели из-за плохой обработки ошибок,
неудобных методов обнаружения конца данных и отсутствия поддержки двоичных
или неблокирующих передач.
PQgetline
Читает строку символов (переданную сервером) с символом перехода строки в буферную строку размером
length
.int PQgetline(PGconn *conn, char *buffer, int length);
Эта функция копирует до
length
-1 символов в буфер и преобразует завершающий символ перехода строки в нулевой байт.PQgetline
возвращаетEOF
в конце ввода, 0, если вся строка была прочитана, и 1, если буфер заполнен, но завершающий символ перехода строки еще не был прочитан.Обратите внимание, что приложение должно проверить, состоит ли новая строка из двух символов
\.
, что указывает на то, что сервер закончил отправку результатов командыCOPY
. Если приложение может получать строки, длина которых превышаетlength
-1 символов, необходимо быть внимательным, чтобы правильно распознать строку\.
(и не ошибочно принять конец длинной строки данных за строку-терминатор).PQgetlineAsync
Читает строку данных
COPY
(передаваемую сервером) в буфер без блокировки.int PQgetlineAsync(PGconn *conn, char *buffer, int bufsize);
Эта функция аналогична
PQgetline
, но ее можно использовать приложениями, которым необходимо асинхронно читать данныеCOPY
, то есть без блокировки. После выполнения командыCOPY
и получения ответаPGRES_COPY_OUT
, приложение должно вызыватьPQconsumeInput
иPQgetlineAsync
до обнаружения сигнала о конце данных.В отличие от
PQgetline
, эта функция берет на себя ответственность за обнаружение конца данных.На каждый вызов,
PQgetlineAsync
вернет данные, если полная строка данных доступна во входном буфере libpq. В противном случае, данные не возвращаются, пока не придет остальная часть строки. Функция возвращает -1, если обнаружен маркер конца копируемых данных, или 0, если данные недоступны, или положительное число, указывающее количество возвращенных байт данных. Если возвращается -1, вызывающая сторона должна следующим вызватьPQendcopy
, а затем вернуться к нормальной обработке.Возвращаемые данные не будут выходить за границы строки данных. Если возможно, целая строка будет возвращена одновременно. Но если буфер, предоставленный вызывающей стороной, слишком мал, чтобы вместить строку, отправленную сервером, то будет возвращена частичная строка данных. С текстовыми данными это можно обнаружить, проверив, является ли последний возвращенный байт символом "\n" или нет. (В бинарном
COPY
необходимо фактически разобрать формат данныхCOPY
для принятия эквивалентного решения). Возвращаемая строка не завершается нулевым символом. (Если нужно добавить завершающий нулевой символ, убедитесь, что передаетеbufsize
, на единицу меньший, чем фактически доступное место).PQputline
Отправляет нуль-терминированную строку на сервер. Возвращает 0 в случае успешной отправки и
EOF
в случае невозможности отправки строки.int PQputline(PGconn *conn, const char *string);
Данные потока
COPY
, отправляемого серией вызововPQputline
, имеют тот же формат, что и данные, возвращаемыеPQgetlineAsync
, за исключением того, что приложения не обязаны отправлять ровно одну строку данных за каждый вызовPQputline
; допустимо отправлять неполные строки или несколько строк за один вызов.Примечание
Перед протоколом 3.0 Tantor SE было необходимо, чтобы приложение явно отправляло два символа
\.
в качестве последней строки, чтобы указать серверу, что оно закончило отправку данныхCOPY
. Хотя такой вариант работает, он устарел, и особое значение\.
может быть удалено в будущем релизе. Достаточно вызватьPQendcopy
после отправки фактических данных.PQputnbytes
Отправляет ненулевую строку без завершающего символа на сервер. Возвращает 0 в случае успеха и
EOF
в случае невозможности отправить строку.int PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
Это точно так же, как
PQputline
, за исключением того, что буфер данных не должен быть завершен нулевым символом, поскольку количество байтов для отправки указывается непосредственно. Используйте эту процедуру при отправке двоичных данных.PQendcopy
Синхронизирует с сервером.
int PQendcopy(PGconn *conn);
Эта функция ожидает, пока сервер завершит копирование. Она должна быть вызвана либо после отправки последней строки на сервер с помощью
PQputline
, либо после получения последней строки от сервера с помощьюPQgetline
. Она должна быть вызвана, иначе сервер будет “выйти из синхронизации” с клиентом. После возврата из этой функции сервер готов принять следующую SQL-команду. Возвращаемое значение равно 0 в случае успешного выполнения, в противном случае ненулевое значение. (ИспользуйтеPQerrorMessage
для получения подробностей, если возвращаемое значение ненулевое).При использовании
PQgetResult
приложение должно отвечать на результатPGRES_COPY_OUT
путем выполнения повторяющихся вызововPQgetline
, за которыми следует вызовPQendcopy
после обнаружения строки-терминатора. Затем оно должно вернуться к циклуPQgetResult
, покаPQgetResult
не вернет нулевой указатель. Аналогично результатPGRES_COPY_IN
обрабатывается серией вызововPQputline
, за которыми следует вызовPQendcopy
, затем возврат к циклуPQgetResult
. Это обеспечит правильное выполнение командыCOPY
, встроенной в серию команд SQL.Старые приложения, скорее всего, отправляют команду
COPY
черезPQexec
и предполагают, что транзакция завершена послеPQendcopy
. Это будет работать правильно только в том случае, еслиCOPY
является единственной командой SQL в строке команды.