Antes de darmos os próximos passos com cursores, vamos alterar nosso código para ficar um pouco mais legível, uma vez que para retornar uma linha de cada vez teremos que fazer a verificação do retorno da função PQexec cada vez que ela for chamada (ou seja, uma vez por linha!), o que resultaria em um código cheio de switch, o que ficaria "feio", mas dizer assim. Criaremos uma função que ficará assim:
int ExecutaComando(const char *comando, PGresult **ptr_resultado)
{
int codigo_retorno = 1;
const char *str_resultado;
PGresult *resultado_local;
printf("
Executando comando: %s
", comando);
/*executa o comando e armazena localmente*/
resultado_local = PQexec(conn, comando);
/*passa o resultado local para o segundo parâmetro da função, para que seja acessível dentro de MAIN*/
*ptr_resultado = resultado_local;
/*Verifica se o comando foi bem sucedido*/
if(!resultado_local)
{
/*Se falhou, imprime mensagem na tela e seta o código de retorno da função como 0 (erro)*/
printf("O comando falhou.
");
codigo_retorno = 0;
}
else
{
/*Se foi sucedido, chamamos PQresultStatus para verificar qual o código de retorno*/
switch(PQresultStatus(resultado_local))
{
case PGRES_COMMAND_OK:
printf("Comando ok, %s linhas afetadas.
", PQcmdTuples(resultado_local));
break;
case PGRES_TUPLES_OK:
printf("A query retornou %d linhas.
", PQntuples(resultado_local));
break;
default:
printf("Error in query: %s
", PQresultErrorMessage(resultado_local));
PQclear(resultado_local);
codigo_retorno = 0;
break;
}
}
/*retorna código de retorno*/
return codigo_retorno;
}
Esta função não tem nenhum mistério, tudo aqui já foi visto, apenas colocamos a execução de um comando e a verificação de retorno dentro da função.
Agora que nosso código vai ficar mais legível, vamos continuar com o básico. Vamos no código abaixo retornar apenas uma linha por vez. Não há mistério nisso, lembra que na declaração do FETCH podemos dizer quantos dados queremos retornar? Nosso código vai ficar assim (lembrando que estamos omitindo a parte aonde abrimos e fechamos a conexão com o banco):
comando_ok = ExecutaComando("BEGIN WORK", &result);
if(comando_ok)
{
PQclear(result);
/*Executa o comando*/
comando_ok = ExecutaComando("DECLARE curr CURSOR FOR SELECT * FROM contatos", &result);
if(comando_ok)
{
PQclear(result);
comando_ok = ExecutaComando("FETCH 1 IN curr", &result);
while(comando_ok && PQntuples(result) > 0)
{
PQclear(result);
ExecutaComando("FETCH NEXT IN curr", &result);
}
}
comando_ok = ExecutaComando("COMMIT WORK", &result);
}
if(comando_ok)
PQclear(result);
A saída do programa será algo assim (no meu caso, a minha tabela tem 5 linhas):
Executando comando: BEGIN WORK
Comando ok, linhas afetadas.
Executando comando: DECLARE curr CURSOR FOR SELECT * FROM contatos
Comando ok, linhas afetadas.
Executando comando: FETCH 1 IN curr
A query retornou 1 linhas.
Executando comando: FETCH NEXT IN curr
A query retornou 1 linhas.
Executando comando: FETCH NEXT IN curr
A query retornou 1 linhas.
Executando comando: FETCH NEXT IN curr
A query retornou 1 linhas.
Executando comando: FETCH NEXT IN curr
A query retornou 1 linhas.
Executando comando: FETCH NEXT IN curr
A query retornou 0 linhas.
Executando comando: COMMIT WORK
Comando ok, linhas afetadas.
Note que quando o cursor atinge o final do conjunto de dados, o comando FETCH NEXT irá retornar zero.