[successivo] [precedente] [inizio] [fine] [indice generale] [parte]


Capitolo 15.   MySQL

MySQL è un server SQL molto usato dagli ISP per la sua velocità di esecuzione e la semplicità di gestione. Il file per lo sviluppo di applicazioni vengono generalmente distribuiti con il pacchetto mysql-devel. In esso vi sono le librerie a runtime libmysqlclient.so e i file di include nella directory /usr/include/mysql.

La libreria è completa; con essa è semplice aprire una connessione ad un database, operare con le query e distribuire le righe in array di caratteri.

Per la corretta installazione del pacchetto di sviluppo fare sempre riferimento alla distribuzione Linux che avete installato. Anche la posizione dei file, come delle librerie potrebbe variare.

15.1   <mysql/mysql.h>

Questo file contiene la definizione dei tipi e dei prototipi delle funzioni della libreria libmysql. Non tutte le funzioni sono indispensabili, a volte sono ridondanti o superate da altre inserite di recente. MySQL è un database in costante aggiornamento per questo alcune funzioni potrebbero non scomparire ma diventare obsolete.

Tipi di dati

Tipo Descrizione
MYSQL La struttura contiene tutte le informazione sulla connessione al server SQL.
MYSQL_FIELD La struttura che contiene tutte le informazioni sui campi della tabella. In essa vi sono le variabili che contengono il nome del campo, tabella, dimensione, tipo... Per mezzo di questa struttura è quindi possibile risalire ad una chiave primaria come a un tipo di dato BLOB.
MYSQL_RES La struttura contiene i risultati di una query. La variabile è sempre di tipo puntatore a MYSQL_RES. Il puntatore a questo tipo va sempre liberato con la funzione mysql_free_result.
MYSQL_ROW La struttura contiene la singola riga restituita da una query. Ogni colonna è inserita come un'array di stringhe.
MYSQL_FIELD_OFFSET Indica la posizione del cursore all'interno della riga.

Alcune funzioni

Prototipo Descrizione
int mysql_affected_rows (MYSQL*); Restituisce il numero di righe interessate dalla query precedente avviata con mysql_query. Il parametro formale è il puntatore alla struttura MYSQL.
void mysql_close (MYSQL*); Chiude la connessione al server MySQL. Il parametro formale è il puntatore alla struttura MYSQL.
MYSQL* mysql_connect (MYSQL*, const char*, const char*, const char*); Apre una connessione ad un server MySQL. Il primo parametro formale è il puntatore al tipo MYSQL; il secondo, terzo e quarto sono nell'ordine i puntatori al nome del nodo connessione, all'utente autorizzato e alla password ad esso associata. Se la connessione non è possibile restituisce NULL; il valore restituito ed il primo parametro formale sono identici.
int mysql_create_db (MYSQL*, const char*); Crea un nuovo database con il nome indicato nel secondo parametro e restituisce 0 in caso di riuscita.
void mysql_data_seek (MYSQL_RES*, unsigned int); Sposta il cursore nella riga indicata dal secondo parametro formale. La prima riga viene numerata con 0. Il primo parametro formale è il puntatore alla struttura ottenuto con mysql_store_result.
int mysql_drop_db (MYSQL*, const char*); Elimina il database indicato nel secondo parametro formale e restituisce 0 in caso di riuscita.
int mysql_eof (MYSQL_RES*); Restituisce 0 se ci sono ancora dati da esaminare. Il parametro formale è il puntatore alla struttura ottenuto con mysql_use_result.
unsigned int mysql_errno (MYSQL*); Restituisce il numero dell'errore legato alle operazioni corrente. Se il valore restituito è zero allora non ce ne sono stati.
char* mysql_error (MYSQL*); Come il precedente solo che restituisce un messaggio invece di un numero.
unsigned int mysql_escape_string (char*, const char*, unsigned int); Il primo parametro formale è il puntatore alla stringa che viene restituita dalla funzione. Il secondo parametro formale è la stringa da codificare in formato SQL. Il terzo argomento, se presente, è il numero di byte da prelevare. Il puntatore restituito deve essere lunga il doppio di quella da codificare, ovviamente bisogna considerare anche il carattere nullo di fine stringa. Il valore di ritorno è il numero di byte della stringa codificata.
MYSQL_FIELD* mysql_fetch_field (MYSQL_RES*); Restituisce un puntatore ad una struttura MYSQL_FIELD che contiene le informazioni sui campi del database prelevati. Ad ogni chaimata avanza al successivo fino a ritornare il valore nullo.
MYSQL_FIELD* mysql_fetch_field_direct (MYSQL_RES*, unsigned int); È equivalente a mysql_fetch_field solo che il numero del campo è specificato nel secondo parametro formale. La numerazione parte da 0.
MYSQL_FIELD* mysql_fetch_fields (MYSQL_RES*); È equivalente a mysql_fetch_field, tuttavia restituisce un puntatore ad un array di strutture MYSQL_FIELD.
unsigned long* mysql_fetch_lengths (MYSQL_RES*); Restituisce un array che contiene le lunghezze dei campi prelevati dalla riga corrente. Questa funzione va chiamata dopo mysql_fetch_row.
MYSQL_ROW mysql_fetch_row (MYSQL_RES*); Restituisce una struttura MYSQL_ROW contenente i valori dei campi della struttura MYSQL_RES che rappresenta il puntatore alla riga corrente. Restituisce valore nullo se non ci sono righe o si verifica un errore generico.
MYSQL_FIELD_OFFSET mysql_field_seek (MYSQL_RES*, MYSQL_FIELD_OFFSET); Sposta il cursore alla posizione indicata dal secondo parametro formale. Il valore di ritorno è la posizione precedente del cursore.
MYSQL_FIELD_OFFSET mysql_field_tell (MYSQL_RES*); Restituisce la posizione del cursore all'interno del campo corrente della riga di risultati.
void mysql_free_result (MYSQL_RES*); Libera le risorse occupate dal primo parametro formale.
char* mysql_get_client_info (void); Restituisce informazioni sulla versione delle librerie libmysql utilizzate.
char* mysql_get_host_info (MYSQL*); Restituisce informazioni relative al nome del nodo MySQL utilizzato e il tipo di connessione attivata.
char* mysql_get_server_info (MYSQL*); Restituisce informazioni sulla versione di server MySQL utilizzato.
char* mysql_info (MYSQL*); Restituisce informazioni sulla query precedente se questa era di tipo: INSERT INTO, LOAD DATA INFILE, ALTER TABLE, INSERT INTO TABLE. Restituisce valore nullo negli altri casi.
MYSQL* mysql_init (MYSQL*); Inizializza una struttura MYSQL per essere utilizzata in seguito con mysql_real_connect. Il parametro formale può essere anche un puntatore nullo, in questo caso si utilizza il puntatore restituito dalla funzione. In caso di errore restituisce un puntatore nullo.
unsigned long long mysql_insert_id (MYSQL*); Restituisce l'ultimo generato da un campo con l'autoincremento attivo.
int mysql_kill (MYSQL*, unsigned long); Restituisce zero se l'operazione di chiusura forzata del thread associato al PID nel secondo parametro formale riesce.
MYSQL_RES* mysql_list_dbs (MYSQL*, const char*); Restituisce una struttura contenente tutti i nomi di database corrispondenti all'espressione regolare SQL passata come secondo parametro formale. Se questo è nullo vengono elencati tutti. Lo spazio occupato dal risultato va inseguito liberato con la funzione mysql_free_result. In caso di errore restituisce un valore nullo.
MYSQL_RES* mysql_list_fields (MYSQL*, const char*, const char*); Restituisce una struttura contenente tutti i campi della tabella passata come secondo parametro formale. Il terzo parametro è una espressione regolare SQL. Se questo è nullo vengono elencate tutti i campi della tabella. Lo spazio occupato dal risultato va inseguito liberato con la funzione mysql_free_result. In caso di errore restiutisce un puntatore nullo.

15.2   Compilare il codice sorgente

Ogni progetto dovrà necessariamente caricare il file mysql.h mentre il linker dovrà richiamare la libreria libmysqlclient.so

Gli esempi della dispensa possono essere tutti compilati con il comando seguente:

$ gcc -o esempio esempio.c -L/usr/lib/mysql -lmysqlclient [Invio]

15.3   La programmazione con MySQL

Gli esempi qui proposti si limitano a spiegare la procedura per effettuare una connessione corretta ad un server MySQL e prelevare i dati dalle tabelle in un database.

15.3.1   Connessione a un server MySQL

Gli esempi nei listati 15.1 e 15.2 mostrano due procedure diverse per effettuare una corretta connessione ad un server MySQL.

Il secondo metodo è da preferire al primo oramai obsoleto.

Listato 15.1. Connessione a un server MySQL (obsoleto).

#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>

const char* host = "localhost"; // host di connessione
const char* database = "mydb";  // database di connessione
const char* db_user = "myuser"; // nome utente per la connessione
const char* db_pass = "mypass"; // password non cifrata

int main ()
{
        MYSQL mysql;

        // restituisce NULL se non avviene con successo
        if (! mysql_connect (&mysql, host, db_user, db_pass)) {
                printf ("Errore nella connessione.\n");
                exit (EXIT_FAILURE);
        }

        // restituisce zero se avviene con successo
        if (mysql_select_db (&mysql, database)) {
                printf ("Errore nella selezione del database.\n");
                exit (EXIT_FAILURE);
        }

        printf ("Connessione avvenuta.\n");

        // chiude le risorse
        mysql_close (&mysql);

        exit (EXIT_SUCCESS);
}

I campi host, database, db_user e db_pass contengono le informazioni rispettivamente del nome dell'host, del nome del database e, se presenti, la username e la password per accedervi. Il tipo è rappresentato da un puntatore a caratteri o eventualemente da un array sempre di caratteri.

La funzione mysql_connect accetta in ordine queste ultime quattro variabili e restituisce il puntatore alla variabile mysql associata alla struttura MYSQL o NULL se in presenza di errore.

In tutti gli esempi è indispensabile cambiare i valori delle variabili precedenti ed inserire campi accettabili per il database MySQL con cui si sta lavorando.

Listato 15.2. Connessione a un server MySql.

#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>

const char* host = "localhost"; // host di connessione
const char* database = "mydb";  // database di connessione
const char* db_user = "myuser"; // nome utente per la connessione
const char* db_pass = "mypass"; // password non cifrata

int main ()
{
        MYSQL mysql;

        // restituisce NULL se non avviene con successo
        if (! mysql_init (&mysql)) {
                printf ("Errore nella allocazione di memoria.\n");
                exit (EXIT_FAILURE);
        }

        if (! mysql_real_connect (&mysql, host, db_user, db_pass, "",
                        0, NULL, 0)) {
                printf ("Errore nella connessione.\n");
                exit (EXIT_FAILURE);
        }

        // restituisce zero se avviene con successo
        if (mysql_select_db (&mysql, database)) {
                printf ("Errore nella selezione del database.\n");
                exit (EXIT_FAILURE);
        }

        printf ("Connessione avvenuta.\n");

        // chiude le risorse
        mysql_close (&mysql);

        exit (EXIT_SUCCESS);
}

La funzione mysql_select_db accetta come primo argomento il puntatore alla variabile associata alla struttura MYSQL, il secondo argomento è il puntatore alla variabile che contiene il nome del database dove accedere. La funzione ritorna il valore 0 in caso di successo.

La funzione mysql_close chiude la connessione e libera le risorse allocate in precedenza.

Per quanto concerne il listato 15.2 potremmo affermare che l'apertura del database può essere effettuata direttamente con mysql_real_connect oppure in un secondo momento con mysql_select_db. È una questione di semplicità e di stile.

15.3.2   Esecuzione di una query

Il programma in listato 15.4 esegue una semplice query; più complesso è invece l'esempio in listato 15.5 dove la query ritorna delle righe che, una volta memorizzate, vengono visualizzate.

Nel primo programma viene creata una tabella con nome logins con tre campi per memorizzare informazioni, del tutto generiche, relative ai dati personali di un utente.

La tabella, una volta creata andrebbe popolata con dei valori. In questo caso consiglio di utilizzare il programma mysql o modificare per esercizio il listato 15.4; in ogni caso la stringa della query dovrà essere la seguente:

INSERT INTO logins ('<var>nome</var>', '<var>cognome</var>', '<var>email</var>');

Listato 15.4. Avvio di una semplice query.

#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>

const char* host = "localhost"; // host di connessione
const char* database = "mydb";  // database di connessione
const char* db_user = "myuser"; // nome utente per la connessione
const char* db_pass = "mypass"; // password non cifrata

int main()
{
        MYSQL mysql;

        char* query = "CREATE TABLE logins (firstname CHAR (30), lastname
                CHAR (30), email CHAR (20));";

        // restituisce NULL se non avviene con successo
        if (! mysql_init (&mysql)) {
                printf ("Errore nella allocazione di memoria.\n");
                exit (EXIT_FAILURE);
        }

        if (! mysql_real_connect (&mysql, host, db_user, db_pass, "",
                        0, NULL, 0)) {
                printf ("Errore nella connessione.\n");
                goto error;
        }

        // restituisce zero se avviene con successo
        if (mysql_select_db (&mysql, database)) {
                printf ("Errore nella selezione del database.\n");
                goto error;
        }

        // esegue la query
        if (mysql_query (&mysql, query)) {
                printf("Errore nella query.\n");
        }

error:
        mysql_close (&mysql);   // chiusura del database

        exit (EXIT_SUCCESS);
}

La funzione mysql_query ritorna un valore diverso da 0 se avviene un errore durante l'esecuzione della query.

Listato 15.5. Una procedura complicata.

#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>

const char* host = "localhost"; // host di connessione
const char* database = "mydb";  // database di connessione
const char* db_user = "myuser"; // nome utente per la connessione
const char* db_pass = "mypass"; // password non cifrata

int main()
{
        MYSQL mysql;
        MYSQL_ROW row;        // la riga
        MYSQL_RES* result;
        MYSQL_FIELD* field;     // il campo ritornato

        int i = 0, j = 0, n_rows = 0;

        char* query = "SELECT * FROM logins;";

        // restituisce NULL se non avviene con successo
        if (! mysql_init (&mysql)) {
                printf ("Errore nella allocazione di memoria.\n");
                exit (EXIT_FAILURE);
        }

        if (! mysql_real_connect (&mysql, host, db_user, db_pass, "",
                        0, NULL, 0)) {
                printf ("Errore nella connessione.\n");
                goto error;
        }

        // restituisce zero se avviene con successo
        if (mysql_select_db (&mysql, database)) {
                printf ("Errore nella selezione del database.\n");
                goto error;
        }

        // esegue la query
        if (mysql_query (&mysql, query)) {
                printf("Errore nella query.\n");
                goto error;
        }

        result = mysql_store_result (&mysql);

        n_rows = mysql_num_rows (result);

        for (j = 0; j < n_rows; j++) {
                i = 0;
                mysql_field_seek (result, 0);           // sposta a inizio riga
                row = mysql_fetch_row (result);      // preleva i dati della riga
                while ((field = mysql_fetch_field (result))) {
                        printf ("%s: ", field->name);     // visualizza il campo
                        printf ("%s\n", row[i++]);          // visualizza il dato del campo
                }

                printf ("\n");
        }

        mysql_free_result (result);

error:
        mysql_close (&mysql);   // chiusura del database

        exit (EXIT_SUCCESS);
}

Il programma in listato 15.5 memorizza i dati della query nella variabile result. Quest'ultima, che è un puntatore ad una struttura MYSQL_RES, è necessaria per prelevare ciclicamente i dati dei campi (nome, cognome e email) ed il loro contenuto.

Ad ogni ciclo è necessario riposizionare il cursore dei campi ad inizio riga con mysql_field_seek.


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome mysql.html

[successivo] [precedente] [inizio] [fine] [indice generale]