Acessando PostgreSQL com C
O PostgreSQL é um dos principais bancos de dados open source do momento. Veremos neste artigo como acessá-lo utilizando a linguagem C.
Parte 5: Inserindo, atualizando e removendo dados
A manipulação de dados no PostgreSQL é extremamente simples. Apenas a chamada a uma função para executar o comando e algumas outras para verificar os resultados são o suficiente.
A função a ser chamada para executar o comando é a PQexec, que tem o seguinte protótipo:
PGresult *PQexec(PGconn *conn, const char *sql_string);
Esta função recebe como parâmetro um objeto de conexão e uma string contendo o comando SQL a ser executado. O resultado pode ser um NULL em casos excepcionais, do contrário, receberemos um ponteiro que pode ser verificado chamando a função PQresultStatus, que receberá como parâmetro o ponteiro retornado por PQexec e irá retornar um enum do tipo ExecStatusType. A função PQresultStatus tem o seguinte protótipo:
ExecStatusType *PQresultStatus(PGresult *result);
Os valores da enum retornada por esta função são:
O valor de retorno da função PQresultStatus nos mostra apenas a ação ocorrida, se quisermos mais detalhes quanto ao resultado, podemos chamar uma outra função, PQresultErrorMessage, que tem o seguinte protótipo:
const char *PQresultErrorMessage(PGresult *result);
Esta função recebe o mesmo parâmetro que a função PQresultStatus, porém o retorno é uma string contendo a mensagem retornada pelo banco.
Uma outra função que pode ter alguma utilidade é a função PQcmdTuples, que retorna o número de linhas afetadas por comandos INSERT, DELETE e UPDATE (para descobrir a quantidade de linhas retornadas por um SELECT existe uma outra função). A função PQcmdTuples tem o seguinte protótipo:
const char *PQcmdTuples(PGresults *result);
O parâmetro de entrada desta função é o mesmo das funções acima, o ponteiro retornado por PQexec, e o retorno, uma string terminada com NULL contendo dígitos em formato de caracteres (atenção a isto, pois a função não retorna um inteiro, como seria mais óbvio).
Para finalizar esta seção, precisamos saber como liberar o objeto de resultado que obtivemos com a função PQexec. Para isso, usamos a função PQclear, que tem o seguinte protótipo:
void PQclear(PQresult *result);
Vamos agora ver na prática como usamos tudo isso:
A função a ser chamada para executar o comando é a PQexec, que tem o seguinte protótipo:
PGresult *PQexec(PGconn *conn, const char *sql_string);
Esta função recebe como parâmetro um objeto de conexão e uma string contendo o comando SQL a ser executado. O resultado pode ser um NULL em casos excepcionais, do contrário, receberemos um ponteiro que pode ser verificado chamando a função PQresultStatus, que receberá como parâmetro o ponteiro retornado por PQexec e irá retornar um enum do tipo ExecStatusType. A função PQresultStatus tem o seguinte protótipo:
ExecStatusType *PQresultStatus(PGresult *result);
Os valores da enum retornada por esta função são:
- PGRES_EMPTY_QUERY - Nada foi feito
- PGRES_COMMAND_OK - O comando foi bem sucedido, mas sem dados retornados.
- PGRES_TUPLES_OK - O comando foi bem sucedido e dados podem ter sido retornados.
- PGRES_COPY_OUT - Uma cópia para um arquivo externo estava em andamento.
- PGRES_COPY_IN - Uma cópia de um arquivo externo estava em andamento.
- PGRES_BAD_RESPONSE - Erro inesperado.
- PGRES_NONFATAL_ERROR - Erro não fatal.
- PGRES_FATAL_ERROR - Erro fatal.
O valor de retorno da função PQresultStatus nos mostra apenas a ação ocorrida, se quisermos mais detalhes quanto ao resultado, podemos chamar uma outra função, PQresultErrorMessage, que tem o seguinte protótipo:
const char *PQresultErrorMessage(PGresult *result);
Esta função recebe o mesmo parâmetro que a função PQresultStatus, porém o retorno é uma string contendo a mensagem retornada pelo banco.
Uma outra função que pode ter alguma utilidade é a função PQcmdTuples, que retorna o número de linhas afetadas por comandos INSERT, DELETE e UPDATE (para descobrir a quantidade de linhas retornadas por um SELECT existe uma outra função). A função PQcmdTuples tem o seguinte protótipo:
const char *PQcmdTuples(PGresults *result);
O parâmetro de entrada desta função é o mesmo das funções acima, o ponteiro retornado por PQexec, e o retorno, uma string terminada com NULL contendo dígitos em formato de caracteres (atenção a isto, pois a função não retorna um inteiro, como seria mais óbvio).
Para finalizar esta seção, precisamos saber como liberar o objeto de resultado que obtivemos com a função PQexec. Para isso, usamos a função PQclear, que tem o seguinte protótipo:
void PQclear(PQresult *result);
Vamos agora ver na prática como usamos tudo isso:
#include <stdio.h>
#include <libpq-fe.h>
/*Objeto de conexão*/
PGconn *conn = NULL;
/*Ponteiro de resultado*/
PGresult *result;
int main()
{
/*realiza a conexão*/
conn = PQconnectdb("host=localhost dbname=TESTE");
if(PQstatus(conn) == CONNECTION_OK)
{
printf("Conexão com efetuada com sucesso. ");
}
else
{
printf("Falha na conexão. Erro: %s", PQerrorMessage(conn));
PQfinish(conn);
return -1;
}
/*Executa o comando*/
/*Aqui você substitui a query por outras. Colocamos apenas uma como exemplo.*/
result = PQexec(conn, "INSERT INTO contatos (email, nome) VALUES ('Luiz Poleto', 'blah@hehe.com')");
if(!result)
{
printf("Erro executando comando. ");
}
else
{
switch(PQresultStatus(result))
{
case PGRES_EMPTY_QUERY:
printf("Nada aconteceu. ");
break;
case PGRES_FATAL_ERROR:
printf("Error in query: %s ", PQresultErrorMessage(result));
break;
case PGRES_COMMAND_OK:
printf("%s linhas afetadas. ", PQcmdTuples(result));
break;
default:
printf("Algum outro resultado ocorreu. ");
break;
}
/*Libera o nosso objeto*/
PQclear(result);
}
/*Verifica se a conexão está aberta e a encerra*/
if(conn != NULL)
PQfinish(conn);
}
#include <libpq-fe.h>
/*Objeto de conexão*/
PGconn *conn = NULL;
/*Ponteiro de resultado*/
PGresult *result;
int main()
{
/*realiza a conexão*/
conn = PQconnectdb("host=localhost dbname=TESTE");
if(PQstatus(conn) == CONNECTION_OK)
{
printf("Conexão com efetuada com sucesso. ");
}
else
{
printf("Falha na conexão. Erro: %s", PQerrorMessage(conn));
PQfinish(conn);
return -1;
}
/*Executa o comando*/
/*Aqui você substitui a query por outras. Colocamos apenas uma como exemplo.*/
result = PQexec(conn, "INSERT INTO contatos (email, nome) VALUES ('Luiz Poleto', 'blah@hehe.com')");
if(!result)
{
printf("Erro executando comando. ");
}
else
{
switch(PQresultStatus(result))
{
case PGRES_EMPTY_QUERY:
printf("Nada aconteceu. ");
break;
case PGRES_FATAL_ERROR:
printf("Error in query: %s ", PQresultErrorMessage(result));
break;
case PGRES_COMMAND_OK:
printf("%s linhas afetadas. ", PQcmdTuples(result));
break;
default:
printf("Algum outro resultado ocorreu. ");
break;
}
/*Libera o nosso objeto*/
PQclear(result);
}
/*Verifica se a conexão está aberta e a encerra*/
if(conn != NULL)
PQfinish(conn);
}
eu imaginava ser mais complicado, pelo fato do unico banco que acessei usando C foi o oracle, qual tinha que dar algumas voltas ate gerar o binario