27.8. Funções associadas ao comando COPY

No PostgreSQL o comando COPY possui opções para ler ou escrever na conexão de rede utilizada pela libpq. As funções descritas nesta seção permitem que os aplicativos aproveitem as vantagens desta capacidade, fornecendo ou recebendo dados copiados.

No processamento global, primeiro o aplicativo envia um comando COPY do SQL através da função PQexec, ou através de uma função equivalente a esta. A resposta a este comando, se não houver erro, é um objeto PGresult contendo o código de status PGRES_COPY_OUT ou PGRES_COPY_IN (dependendo da direção especificada para a cópia). Depois, o aplicativo deve utilizar as funções descritas nesta seção para receber ou transmitir as linhas de dados. Quando a transferência de dados estiver completa, será retornado outro objeto PGresult indicando se a transferência foi bem ou mal-sucedida. O status será PGRES_COMMAND_OK para transferência bem-sucedida, ou PGRES_FATAL_ERROR caso ocorra algum problema. Neste ponto, podem ser enviados outros comandos SQL através da função PQexec (Não é possível executar outros comandos SQL utilizando a mesma conexão enquanto a operação de cópia estiver em andamento).

Se o comando COPY for executado através da função PQexec em uma cadeia de caracteres podendo conter outros comandos, o aplicativo deve continuar recebendo os resultados através da função PQgetResult após terminar a seqüência do COPY. Somente quando a função PQgetResult retorna NULL tem-se certeza que a cadeia de caracteres de comando da função PQexec está concluída, e é seguro executar mais comandos.

As funções desta seção somente devem ser executadas após receber o status PGRES_COPY_OUT ou PGRES_COPY_IN no resultado de PQexec ou PQgetResult.

O objeto PGresult contendo um destes valores no status possui dados adicionais sobre a operação COPY iniciando. Este dados adicionais estão disponíveis através de funções também utilizadas com os resultados dos comandos na conexão:

PQnfields

Retorna o número de colunas (campos) a serem copiados.

PQbinaryTuples

0 indica que o formato global da cópia é textual (linhas separadas pelo caractere de nova-linha, colunas separadas pelo separador de caracteres, etc). 1 indica que o formato global da cópia é binário. Para obter informações adicionais deve ser consultado o comando COPY.

PQfformat

Retorna o código do formato (0 para texto, 1 para binário) associado com cada coluna da operação de cópia. Os códigos de formato por-coluna são sempre iguais a zero quando o formato global da cópia é textual, mas o formato binário permite tanto colunas binárias quanto texto (Entretanto, na implementação corrente do comando COPY, somente estão presentes colunas binárias na cópia binária; portanto, no momento os formatos por-coluna sempre correspondem ao formato global).

Nota: Estes valores de dados adicionais somente estão disponíveis quando se utiliza o protocolo 3.0. Quando se utiliza o protocolo 2.0, todas estas funções retornam 0.

27.8.1. Funções para enviar os dados do COPY

Estas funções são utilizadas para enviar os dados durante COPY FROM STDIN, e falham quando são chamadas em conexões que não se encontram no estado COPY_IN.

PQputCopyData

Envia dados para o servidor durante o estado COPY_IN.

int PQputCopyData(PGconn *conn,
                  const char *buffer,
                  int nbytes);

Transmite para o servidor os dados do COPY no buffer especificado, com comprimento nbytes. O resultado será igual a 1 se o dado for enviado, zero se não for enviado porque a tentativa bloquearia (este caso somente é possível se a conexão for no modo não bloqueante), ou -1 caso ocorra um erro (Quando o valor retornado for igual a -1 deverá ser utilizada a função PQerrorMessage para obter detalhes. Se o valor retornado for igual a zero, deve-se aguardar por pronto-para-escrever e tentar novamente).

O aplicativo pode dividir o fluxo de dados do COPY em cargas de buffer de qualquer tamanho conveniente. As fronteiras do buffer de carga não possuem significado semântico ao enviar. O conteúdo do fluxo de dados deve corresponder ao formato esperado pelo comando COPY; para obter detalhes deve ser visto o comando COPY.

PQputCopyEnd

Envia a indicação de fim de dados para o servidor durante o estado COPY_IN.

int PQputCopyEnd(PGconn *conn,
                 const char *errormsg);

Termina a operação COPY_IN com sucesso se errormsg for NULL. Se errormsg não for NULL, então o COPY é obrigado a falhar, com a cadeia de caracteres apontada por errormsg usada como mensagem de erro (Entretanto, não se deve assumir que virá do servidor uma determinada mensagem, porque o servidor pode falhar na execução do comando COPY por seus próprios motivos. Também deve ser observado que forçar a falha não funciona quando se utiliza conexões com protocolo pré-3.0).

O resultado será igual a 1 se o dado de terminação for enviado, zero se não for enviado porque a tentativa bloquearia (este caso somente é possível se a conexão for no modo não bloqueante), ou -1 caso ocorra um erro (Quando o valor retornado for igual a -1 deverá ser utilizada a função PQerrorMessage para obter detalhes. Se o valor retornado for igual a zero, deve-se aguardar por pronto-para-escrever e tentar novamente).

Após uma chamada bem-sucedida à função PQputCopyEnd, deve ser chamada a função PQgetResult para obter o status final do resultado do comando COPY. Deve-se aguardar por este resultado da maneira usual. Em seguida voltar à operação normal.

27.8.2. Funções para receber os dados do COPY

Estas funções são utilizadas para receber os dados durante COPY TO STDOUT, e falham quando são chamadas em conexões que não se encontram no estado COPY_OUT.

PQgetCopyData

Recebe dados do servidor durante o estado COPY_OUT.

int PQgetCopyData(PGconn *conn,
                  char **buffer,
                  int async);

Tenta obter outra linha de dados do servidor durante o COPY. Os dados são sempre retornados uma linha de cada vez; se estiver disponível apenas uma linha parcial, esta não é retornada. O retorno bem-sucedido da linha de dados envolve a alocação de um bloco de memória para conter os dados. O parâmetro buffer deve ser diferente de NULL. O parâmetro *buffer é definido para apontar para a memória alocada, ou para NULL nos casos em que nenhum buffer é retornado. Um buffer de resultado diferente de NULL deve ser liberado através da função PQfreemem quando não for mais necessário.

Quando uma linha é retornada com sucesso, o valor retornado é o número de bytes de dados na linha (sempre será maior que zero). A cadeia de caracteres retornada é sempre terminada por nulo, embora provavelmente somente será útil para o comando COPY no formato texto. Um resultado igual a zero indica que o comando COPY ainda se encontra em andamento, mas que nenhuma linha está disponível no momento (isto somente é possível quando o parâmetro async é igual a verdade). O resultado com valor -1 indica que o comando COPY chegou ao fim. O resultado -2 indica que ocorreu um erro (deve ser consultada a função PQerrorMessage para saber o motivo).

Quando o valor do parâmetro async é igual a verdade (diferente de zero), a função PQgetCopyData não bloqueia aguardando pela entrada, e retorna zero se o comando COPY ainda estiver em andamento mas não existir nenhuma linha completa disponível (Neste caso deve-se aguardar por pronto-para-ler antes de tentar novamente; não importa se foi chamada a função PQconsumeInput). Quando async é falso (zero), a função PQgetCopyData bloqueia até que haja dados disponíveis, ou que a operação complete.

Após a função PQgetCopyData retornar o valor -1, deve-se chamar a função PQgetResult para obter o status do resultado final do comando COPY. Deve-se aguardar por este resultado da maneira usual. Em seguida voltar à operação normal.

27.8.3. Funções obsoletas para o COPY

Estas funções representam métodos antigos para tratar o comando COPY. Embora ainda funcionem, estão em obsolescência devido a um fraco tratamento de erros, métodos inconvenientes para detectar o fim dos dados, e falta de suporte para transferências binárias e não bloqueantes.

PQgetline

Lê uma linha terminada pelo caractere nova-linha (transmitida pelo servidor) em um buffer cadeia de caracteres com comprimento length.

int PQgetline(PGconn *conn,
              char *buffer,
              int length);

Esta função copia até length-1 caracteres para o buffer e converte o caractere nova-linha terminador em um byte zero. A função PQgetline retorna EOF no final da entrada, 0 se toda a linha já foi lida, e 1 se o buffer estiver cheio mas o caractere nova-linha terminador ainda não foi lido.

Deve ser observado que o aplicativo precisa verificar se a nova linha consiste nos dois caracteres \., indicando que o servidor terminou de enviar os resultados do comando COPY. Se o aplicativo puder receber linhas com comprimento maior que length-1 caracteres, deve-se tomar o cuidado que este reconheça \. corretamente (e, por exemplo, não confunda o final de uma linha de dados longa com a linha terminadora).

PQgetlineAsync

Lê uma linha de dados do COPY (transmitida pelo servidor) em um buffer sem bloquear.

int PQgetlineAsync(PGconn *conn,
                   char *buffer,
                   int bufsize);

Esta função é semelhante à função PQgetline, mas pode ser utilizada por aplicativos que devem ler os dados do COPY assincronamente, ou seja, sem bloquear. Uma vez emitido o comando COPY e obtida uma resposta PGRES_COPY_OUT, o aplicativo deve chamar PQconsumeInput e PQgetlineAsync até que o sinal de fim dos dados seja detectado.

Ao contrário de PQgetline, esta função recebe a responsabilidade de detectar o fim dos dados.

A cada chamada, PQgetlineAsync retorna dados se estiver disponível no buffer de entrada da libpq uma linha de dados completa. Senão, nenhum dado é retornado até que o restante da linha chegue. A função retorna -1 quando a marca de fim-de-dados-de-cópia (end-of-copy-data) é reconhecida, ou 0 quando não há dados disponíveis, ou um número positivo indicando o número de bytes de dados retornados. Se for retornado -1, quem chamou deve chamar PQendcopy em seguida, e depois retornar ao processamento normal.

Os dados retornados não vão além da fronteira dos dados da linha. Se for possível, é retornada uma linha inteira de cada vez. Mas se o buffer oferecido por quem chama for muito pequeno para guardar uma linha enviada pelo servidor, então são retornados dados parciais da linha. Com dados no formato texto isto pode ser detectado testando se o último byte retornado é \n, ou não (Em um comando COPY binário, será necessária a análise do formato real dos dados do COPY para fazer uma determinação equivalente). A cadeia de caracteres retornada não é terminada por nulo (Se for desejado adicionar um nulo terminador, deve-se ter certeza de passar bufsize com tamanho de um caractere a menos que espaço realmente disponível).

PQputline

Envia uma cadeia de caracteres terminada por nulo para o servidor. Retorna 0 quando é bem-sucedida, e EOF quando não consegue enviar a cadeia de caracteres.

int PQputline(PGconn *conn,
              const char *string);

O fluxo de dados do COPY enviado por uma série de chamadas à função PQputline possui o mesmo formato que o retornado pela função PQgetlineAsync, exceto que os aplicativos não são obrigados a enviar uma linha de dados por chamada à função PQputline; não há problema em se enviar uma linha parcial, ou várias linhas por chamada.

Nota: Antes do protocolo 3.0 do PostgreSQL, era necessário que o aplicativo enviasse explicitamente os dois caracteres \. como linha final para indicar ao servidor que tinha terminado de enviar os dados do comando COPY. Embora isto ainda funcione, está em obsolescência e pode ser esperado que seja removido o significado especial de \. em uma versão futura. Basta chamar a função PQendcopy após ter enviado os dados.

PQputnbytes

Envia uma cadeia de caracteres não terminada por nulo para o servidor. Retorna 0 quando é bem-sucedida, e EOF quando não consegue enviar a cadeia de caracteres.

int PQputnbytes(PGconn *conn,
                const char *buffer,
                int nbytes);

É exatamente igual a PQputline, exceto que o buffer dos dados não precisa ser terminado por nulo, uma vez que o número de bytes a serem enviados é especificado diretamente. Deve ser utilizada esta função quando se envia dados binários.

PQendcopy

Sincroniza com o servidor.

int PQendcopy(PGconn *conn);

Esta função aguarda até que o servidor tenha terminado de copiar. Deve ser chamada quando a última cadeia de caracteres já tiver sido enviada para o servidor utilizando PQputline, ou quando a última cadeia de caracteres tiver sido recebida do servidor utilizando PGgetline. Deve ser chamada ou o servidor ficará "fora de sincronia" com o cliente. Após o retorno desta função, o servidor está pronto para receber o próximo comando SQL. Retorna o valor 0 ao término bem-sucedido, ou um valor diferente de zero caso contrário (Quando o valor retornado for diferente de zero, deve ser utilizada a função PQerrorMessage para obter detalhes).

Quando se usa PQgetResult, o aplicativo deve responder ao resultado PGRES_COPY_OUT executando PQgetline repetidamente, seguida por PQendcopy após ter encontrado a linha terminadora. Depois deve voltar ao laço PQgetResult até que PQgetResult retorne um ponteiro nulo. De forma semelhante, um resultado PGRES_COPY_IN é processado por uma série de chamadas a PQputline seguida por PQendcopy, e depois retornar ao laço PQgetResult. Este arranjo garante que o comando COPY incorporado a uma série de comandos SQL será executado de maneira correta.

Os aplicativos antigos provavelmente enviam o comando COPY através da função PQexec e assumem que a transação está terminada após PQendcopy. Isto funciona de maneira correta somente se o comando COPY for o único comando SQL na cadeia de caracteres do comando.

SourceForge.net Logo CSS válido!