27.4. Processamento de comandos assíncronos

A função PQexec é adequada para a submissão de comandos em aplicativos normais, síncronos. Entretanto, possui algumas deficiências importantes para alguns usuários:

Os aplicativos insatisfeitos com estas limitações podem, em vez desta, utilizar as funções subjacentes a partir das quais PQexec é construída: PQsendQuery e PQgetResult. Também existem as funções PQsendQueryParams, PQsendPrepare e PQsendQueryPrepared, que podem ser utilizadas com PQgetResult para duplicar as funcionalidades de PQexecParams, PQprepare e PQexecPrepared, respectivamente.

PQsendQuery

Submete o comando ao servidor sem aguardar pelos resultados. Retorna 1 quando o envio do comando é bem-sucedido, e 0 caso contrário (neste caso, deve ser usada a função PQerrorMessage para obter informações adicionais sobre a falha).

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

Após uma chamada bem-sucedida à função PQsendQuery, deve ser chamada a função PQgetResult uma ou mais vezes para obter os resultados. A função PQsendQuery não deve ser chamada novamente (na mesma conexão), até que a função PQgetResult retorne um ponteiro nulo, indicando que o comando completou.

PQsendQueryParams

Submete o comando e os parâmetros em separado para o servidor, sem aguardar pelos resultados.

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

É equivalente à função PQsendQuery, exceto que os parâmetros podem ser especificados separados da cadeia de caracteres do comando. Os parâmetros da função são tratados de forma idêntica aos da função PQexecParams. Da mesma forma que a função PQexecParams, não funciona em conexões com protocolo 2.0, e permite apenas um comando na cadeia de caracteres de comando.

PQsendPrepare

Envia uma solicitação para criar uma declaração preparada com os parâmetros fornecidos, sem aguardar completar.

int PQsendPrepare(PGconn *conn,
                  const char *stmtName,
                  const char *query,
                  int nParams,
                  const Oid *paramTypes);

Esta é a versão assíncrona da função PQprepare: retorna 1 se for capaz de enviar a solicitação, e 0 caso contrário. Após uma chamada bem sucedida, deve ser chamada a função PQgetResult para determinar se a criação da declaração preparada no servidor foi bem-sucedida. Os parâmetros desta função são tratados de maneira idêntica aos da função PQprepare. Da mesma forma que a função PQprepare, não funciona em conexões com protocolo 2.0.

PQsendQueryPrepared

Envia solicitação para executar a declaração preparada com os parâmetros fornecidos, sem aguardar pelos resultados.

int PQsendQueryPrepared(PGconn *conn,
                        const char *stmtName,
                        int nParams,
                        const char * const *paramValues,
                        const int *paramLengths,
                        const int *paramFormats,
                        int resultFormat);

Semelhante à função PQsendQueryParams, mas o comando a ser executado é especificado pelo nome da declaração preparada anteriormente, em vez de fornecer a cadeia de caracteres do comando. Os parâmetros desta função são tratados de maneira idêntica aos da função PQexecPrepared. Da mesma forma que a função PQexecPrepared, não funciona em conexões com protocolo 2.0.

PQgetResult

Aguarda o próximo resultado de uma chamada anterior a PQsendQuery, PQsendQueryParams, PQsendPrepare ou PQsendQueryPrepared, e retorna o resultado. Retorna um ponteiro nulo quando o comando está completo e não haverão mais resultados.

PGresult *PQgetResult(PGconn *conn);

A função PQgetResult deve ser chamada repetidas vezes até que retorne um ponteiro nulo, indicando que o comando completou (Se for chamada quando nenhum comando estiver ativo, a função PQgetResult apenas retorna o ponteiro nulo de uma vez). Cada resultado não-nulo da função PQgetResult deve ser processado usando as mesmas funções de acesso a PGresult descritas anteriormente. Não se deve esquecer de liberar cada objeto de resultado através de PQclear após terminar de usá-lo. Deve ser observado que a função PQgetResult somente bloqueia se um comando estiver ativo, e os dados de resposta necessários ainda não foram lidos por PQconsumeInput.

A utilização da função PQsendQuery juntamente com a função PQgetResult resolve um dos problemas da função PQexec: Se uma cadeia de caracteres de comando incluir vários comandos SQL, os resultados destes comandos podem ser obtidos individualmente (Isto permite uma forma simples de processamento sobreposto, da seguinte maneira: o cliente pode estar tratando os resultados de um comando, enquanto o servidor ainda está trabalhando em comandos posteriores na mesma cadeia de caracteres de comando). Entretanto, chamar PQgetResult ainda faz com que o cliente fique bloqueado até que o servidor complete o próximo comando SQL. Isto pode ser evitado pelo uso apropriado de mais duas funções:

PQconsumeInput

Se estiver disponível uma entrada vinda do servidor, receber esta entrada.

int PQconsumeInput(PGconn *conn);

A função PQconsumeInput normalmente retorna 1, indicando "nenhum erro", mas retorna 0 caso tenha acontecido algum problema (neste caso a função PQerrorMessage pode ser consultada). Deve ser observado que o resultado não informa se algum dado de entrada foi realmente coletado. Após chamar a função PQconsumeInput, o aplicativo pode verificar PQisBusy e/ou PQnotifies para ver se seu estado mudou.

A função PQconsumeInput pode ser chamada mesmo que o aplicativo ainda não esteja preparado para tratar o resultado ou a notificação. A função lê os dados disponíveis e guarda em um buffer, fazendo, portanto, com que uma indicação de pronto-para-ler da função select() desapareça. O aplicativo pode, portanto, utilizar a função PQconsumeInput para limpar a condição da função select() imediatamente, e depois examinar os resultados quando achar melhor.

PQisBusy

Retorna 1 se o comando estiver ocupado, ou seja, a função PQgetResult fica bloqueada aguardando pela entrada. O retorno do valor 0 indica que a função PQgetResult pode ser chamada com garantia que não vai bloquear.

int PQisBusy(PGconn *conn);

A função PQisBusy não tenta por si mesma ler os dados do servidor; portanto, a função PQconsumeInput deve ser chamada antes, ou o estado de ocupado nunca vai terminar.

Um aplicativo utilizando estas funções tipicamente tem um laço principal que usa a função select() ou poll() para aguardar por todas as condições que deve responder. Uma das condições é entrada disponível vinda do servidor, que em termos da função select() significa dados legíveis no descritor de arquivo identificado pela função PQsocket. Quando o laço principal detecta uma entrada pronta, deve chamar a função PQconsumeInput para ler a entrada. Depois pode chamar PQisBusy, seguida por PQgetResult, se PQisBusy retornar falso (0). Também pode chamar PQnotifies para detectar mensagens de NOTIFY (consulte a Seção 27.7).

Um cliente que utiliza as funções PQsendQuery/PQgetResult também pode tentar cancelar um comando que ainda está sendo processado pelo servidor; consulte a Seção 27.5. Mas a despeito do valor retornado por PQcancel, o aplicativo deve continuar com a seqüência normal de leitura de resultado utilizando PQgetResult. Um cancelamento bem-sucedido simplesmente faz com que o comando termine mais cedo do que faria de outra maneira.

Utilizando as funções descritas acima é possível evitar o bloqueio ao aguardar pela entrada vindo do servidor. Entretanto, ainda é possível que o aplicativo fique bloqueado aguardando para enviar a saída para o servidor. Isto é relativamente incomum, mas pode acontecer se forem enviados comandos SQL ou valores de dados muito longos (Entretanto, é muito mais provável quando o aplicativo envia dados através do comando COPY IN). Para evitar esta possibilidade, e obter uma operação com o banco de dados totalmente sem bloqueio, podem ser utilizadas as seguintes funções adicionais.

PQsetnonblocking

Define o status da conexão como bloqueante ou não.

int PQsetnonblocking(PGconn *conn, int arg);

Define o status da conexão como não bloqueante se arg for igual a 1, ou bloqueante se arg for igual a 0. Retorna 0 se for bem-sucedida, ou -1 se houver um erro.

No estado não bloqueante, a chamada a PQsendQuery, PQputline, PQputnbytes e PQendcopy não bloqueia, mas em vez disso retorna um erro se precisarem ser chamadas novamente.

Deve ser observado que a função PQexec não respeita o modo não bloqueante; se for chamada, age do modo bloqueante de qualquer maneira.

PQisnonblocking

Retorna o status da conexão com o banco de dados como bloqueante ou não.

int PQisnonblocking(const PGconn *conn);

Retorna 1 se a conexão estiver definida no modo não bloqueante, e 0 se bloqueante.

PQflush

Tenta descarregar qualquer dado de saída enfileirado para o servidor. Retorna 0 se for bem sucedido (ou se a fila de envio estiver vazia), -1 se falhar por alguma razão, ou 1 se não for capaz de enviar todos os dados ainda na fila de envio (este caso somente pode ocorrer se a conexão não for bloqueante).

int PQflush(PGconn *conn);

Após enviar qualquer comando ou dado por uma conexão não bloqueante, deve ser chamada a função PQflush. Se retornar 1, deve ser aguardado até que o soquete esteja pronto-para-escrita, e chamá-la novamente; repetir até que retorne 0. Uma vez que a função PQflush retorne 0, deve-se aguardar para que o soquete esteja pronto-para-leitura, e depois ler a resposta conforme descrito acima.

SourceForge.net Logo CSS válido!