domingo, 18 de março de 2018

Criando uma API em C para usar com CFFI - PostgreSQL

Uma lib bem legal do Postgres é a libpq.

Instalação no Debian 7, 8 e 9:

sudo apt update && sudo apt install libpq-dev


Ela pode ser usada com C ou C++.

Pequeno exemplo em C:
Includes: libpq-fe.h, stdio.h, stdlib.h, locale.h.

#define URL_CONN "dbname=mydatabase host=xx.xx.xx.xx user=postgres password=secret" 

typedef struct { 
    int n_rows;
    int n_cols; 
    char ** col_names;   
    PGresult *result;    
    PGconn * conn;
} Pq_reasult;

void pq_execute_query(char * sql){  
    setlocale(LC_ALL, "");
    Pq_reasult * pq = (Pq_reasult *) malloc(sizeof(Pq_reasult));
    pq->conn = PQconnectdb(URL_CONN); 

    if (PQstatus(pq->conn) == CONNECTION_BAD) {
        puts("Falha ao conectar ao Posgres!");
        exit(0);
    }
    
    PGresult * res = PQexec(pq->conn, sql);
    pq->result = res;
    
    if (PQresultStatus(pq->result) != PGRES_TUPLES_OK) {
        puts("0 linhas retornadas!"); 
    }     
    pq->n_rows = PQntuples(pq->result);
    pq->n_cols = PQnfields(pq->result); 

    if(pq->result != NULL){
        int row, col;  
        char * arr_res[pq->n_rows][pq->n_cols]; 
        
        for (row = 0; row < pq->n_rows; row++) {
            for (col = 0; col < pq->n_cols; col++) { 
                arr_res[row][col] = PQgetvalue(pq->result, row, col);
            } 
        }

        printf("Retornadas %d colunas.\n", (size_t)sizeof(arr_res[0]) /sizeof(*arr_res[0]));
        printf("Retornadas %d linhas.\n", (size_t)sizeof(arr_res) /sizeof(*arr_res)); 
        
   
        char * arr[pq->n_cols];
        for (col = 0; col < pq->n_cols; col++) {
            arr[col] = PQfname(pq->result, col); 
        }
        pq->col_names = &arr[0]; 
        
        int c;
        for(c = 0; c < pq->n_cols; c++){
            printf("%s\t", pq->col_names[c]);            
        }
        puts("");
        puts("==========================");
        
        for (row = 0; row < pq->n_rows; row++) {
            for (col = 0; col < pq->n_cols; col++) {
                printf("%s\t", arr_res[row][col]);
            }
            puts("");
        }

        puts("==========================");
    }
    PQclear(pq->result);
    PQfinish(pq->conn);  
} 


int main(void) {             

    return (EXIT_SUCCESS);
}
 
Vamos dar o nome do arquivo .c de "pg_foo.c".
Para linkar, no terminal digite:
$ gcc -c pg_foo.c -I /usr/include/postgresql/ -Wall -fPIC



A opção "-Wall -fPIC" é para que a lib gerada seja dinâmica. Não tem como compilar ela de modo estático. Vamos compilar:
$ gcc -shared -o libpq_query.dll pg_foo.o -I /usr/include/postgresql/ -lpq

Funciona tanto no Windows com MinGW como no Linux.

Vamos consumir com CFFI para usar com PyPy.
Baixando o PyPy:
$ wget https://bitbucket.org/pypy/pypy/downloads/pypy2-v5.10.0-linux64.tar.bz2

Extraindo:
$ tar jxf ./pypy2-v5.10.0-linux64.tar.bz2 

Vamos jogar na opt:
$ sudo mv ./pypy2-v5.10.0-linux64 /opt/pypy





Adicionar o PyPy ao PATH, no /etc/profile inclua:
export PATH=/opt/pypy/bin:$PATH




De um source:
$ source /etc/profile




Instalar o pip no PyPy para simplificar as coisas:
$ cd /opt/pypy/bin/
$ curl -O https://bootstrap.pypa.io/get-pip.py
$ sudo pypy get-pip.py

Instalando o CFFI:
sudo pypy -m pip install cffi

E finalmente:

import cffi
 
ffi = cffi.FFI()
ffi.cdef("void pq_execute_query(char * sql);") 
C = ffi.dlopen("./libpq_query.dll")

C.pq_execute_query(b" SELECT * FROM conta_contabil LIMIT 20;")

Setup do Postgresql - Debian 9

Entre os melhores Sistemas de Gerenciamento de Banco de Dados (SGBDs) da atualidade estão:

Oracle: Porque é caro;
Microsoft SQL Server: Porque é barato;
SQLIte: Porque é leve, simplificado, self-contained e de domínio público;
MariaDB (MySQL): Porque é Software Livre;
PostgreSQL: Porque é Software Livre;

1 - Oracle:
Se você tem um sistema grande e complexo com algumas dezenas/centenas/milhares de usuários e precisa de um bom suporte técnico, que que o suporte seja prestado por uma empresa e precisa armazenas dados binários no SGBD (imagens, streaming, áudio, etc... - não faça isso a menos que tem um bom motivo...), então talvez use o Oracle, prepare seu bolso...

2 - SQL Server:
Se você se enquadra na situação 1, mas quer ter um custo menor, talvez use o SQL Server. A Microsoft gosta de você.

3 - SQLite:
Se você está em um cenário com bem poucos usuários, onde os acessos ao banco de dados quase nunca são simultâneos/concorrentes, ou o sistema tenha apenas 1 usuário, mesmo que o volume de dados seja de médio para grande, se você não for fazer muitas consultas complexas: esse "carinha" é a melhor opção pra você.

4 - MariaDB
Se você entende a filosofia de Software Livre e sabe o que significa o trabalho da Comunidade do Software Livre/Open Source, e está em um cenário multi-usuário, com transações concorrentes, mas precisa apenas armazenar e recuperar dados (CRUDs), tem profissonas na sua equipe que entendem isso e sabem buscar/oferecer ajuda: então o MariaDB (MySQL) te oferece uma performance melhor hoje (futuramente isso pode mudar).

5 - PostgreSQL
Se você tem uma situação semelhante à anterior, mas além de meramente armazenar dados, precisa gerar relatórios complexos, alguns com muitas JOINs/Sub-consultas, e precisa de um SGBD mais robusto, o PostgreSQL pode ser sua melhor escolha.

Recentemente me surgiu a necessidade de montar uma espécie de Data warehouse na empresa. Mas além de servir como armazém da dedos para geração de relatórios (alguns deles um pouco pesados), eu gostaria também de "aproveitar" essa instância de SGBD para alguns CRUDs, adivinha qual SQGB escolhi?

INSTALAÇÃO DO POSTGRES NO DEBIAN 9

$ sudo apt update && sudo apt install postgresql postgresql-common -y




Você também pode precisar desse (principalmente se for desenvolver em C ):


$ sudo apt install libpq-dev





Se quiser gerenciar o BD em modo gráfico:


$ sudo apt install pgadmin3

Mudando a senha do root

Digite:

$ sudo -u postgres psql


\password

Você deve ver algo assim (crie a senha, "\q" sai do console):

user@deb-ctb:~$ sudo -u postgres psql
psql (9.6.7)
Digite "help" para ajuda.

postgres=# \password
Digite nova senha:
Digite-a novamente:
postgres=# \q
user@deb-ctb:~$

Entramos no console do Postgres com o usuário padrão (postgres), e criamos senha dele.
Isso já deve te dar acesso em modo local ao PG Admin.
Você pode criar bases de dados, restaurar backups, etc.

Mas por padrão o Postgres não libera acesso remoto (em rede), você precisa configurar isso manualmente. Não precisa dizer que é por motivos de segurança.

Uma forma bem liberal e permissiva de fazer isso é aceitar conexões de qualquer lugar.
O ideal seria permitir somente os endereços dos clientes que você confia pra acessar a base remotamente... Se sua aplicação é Web e está em localhost (127.0.0.1) você nem precisa fazer isso, mas... por sua conta e risco (e sempre é):

Edite o arquivo pg_hba.conf:

$ sudo nano /etc/postgresql/9.6/main/pg_hba.conf

Encontre a seguinte linha:

# IPv4 local connections:
host    all          all          127.0.0.1/32         md5

E deixe assim:

# IPv4 local connections:
host    all          all          0.0.0.0/0            md5

No postgresql.conf (pasta /etc/postgresql/9.6/main/) vamos editar a seguinte linha:

#listen_addresses = 'localhost'    # what IP address(es) to listen on;


Descomente ela e deixe: '*' em vez de: 'localhost':

listen_addresses = '*'         # what IP address(es) to listen on;

E reinicie o BD:

user@deb-ctb:~$ sudo /etc/init.d/postgresql restart
[ ok ] Restarting postgresql (via systemctl): postgresql.service.
user@deb-ctb:~$

Pronto! A parte fácil já foi, agora é só usar.

Criando uma API em C para usar com CFFI - PostgreSQL

Uma lib bem legal do Postgres é a libpq . Instalação no Debian 7, 8 e 9: sudo apt update && sudo apt install libpq-dev Ela po...