C++ e MySQL
Connettersi a MySQL tramite un programma scritto in C++ è possibile utilizzando i driver messi a disposizione sul sito di MySQL.
Essi sono scaricabili da qui: http://www.mysql.com/products/connector/.
La compilazione dei sorgenti è relativamente semplice.
Posizionandoci sulla cartella dei sorgenti, creiamo i Makefile e utilizziamo make:
antonio@antonio-net:~$ cd Desktop/mysql-connector-c++-1.0.5/ antonio@antonio-net:~/Desktop/mysql-connector-c++-1.0.5/$ cmake . antonio@antonio-net:~/Desktop/mysql-connector-c++-1.0.5/$ make clean antonio@antonio-net:~/Desktop/mysql-connector-c++-1.0.5/$ make
ed infine make install oppure copiare la directory cppconn e le librerie in driver dove si vuole (ad esempio in /usr/local/include e /usr/local/lib, rispettivamente).
Le classi che utilizzeremo saranno:
Driver | Consente la connessione al database |
Connection | Rappresenta la connessione al database |
Statement | Rappresenta una semplice query |
PreparedStatement | Rappresenta query con parametri settabili successivamente |
ResultSet | Rappresenta il valore di ritorno di una query |
ResultSetMetaData | Contiene i metadati relativi al resultset |
Per i nosti esempi, creiamo un file my.sql:
drop database if exists test; create database test; use test; create table persone( cod varchar(16) primary key, name varchar(30) not null ); insert into persone (cod, name) values ('blabla1', 'Antonio'), ('blabla2', 'Mario'), ('blabla3', 'Marco'), ('blabla4', 'Aldo'), ('blabla5', 'Giovanni');
e utilizziamo il client di mysql per dare tale file in input:
mysql> \. /home/antonio/Desktop/my.sql Query OK, 1 row affected (0,00 sec) Query OK, 1 row affected (0,00 sec) Database changed Query OK, 0 rows affected (0,09 sec) Query OK, 5 rows affected (0,00 sec) Records: 5 Duplicates: 0 Warnings: 0
Il nostro primo esempio mostrerà come recuperare i dati dalla tabella persone ordinandoli per nome:
#include <string> #include <iostream> #include <cppconn/driver.h> #include <cppconn/connection.h> #include <cppconn/exception.h> #include <cppconn/statement.h> #include <cppconn/resultset.h> #include <cppconn/resultset_metadata.h> using namespace std; const string user = "root"; const string passwd = "secret"; const string database = "test"; const string dbhost = "tcp://127.0.0.1:3306"; int main() { sql::Driver* driver; sql::Connection* connection; sql::Statement* stmt; sql::ResultSet* res; sql::ResultSetMetaData* res_md; string query = "SELECT cod, name FROM persone ORDER BY name"; try { // stabiliamo la connesione e selez. il db driver = get_driver_instance(); connection = driver->connect(dbhost, user, passwd); connection->setSchema(database); // creiamo uno statement stmt = connection->createStatement(); // eseguiamo la query res = stmt->executeQuery(query); // otteniamo i metadati res_md = res->getMetaData(); // contiamo le righe ottenute cout << ">> Presi " << res->rowsCount() << " record <<" << endl << endl; // stampiamo i nomi dei campi for(int i = 1; i <= res_md->getColumnCount(); i++) cout << res_md->getColumnLabel(i) << "\t\t"; cout << endl << endl; // fetch dei dati while(res->next()) { for(int i = 1; i <= res_md->getColumnCount(); i++) cout << res->getString(i) << "\t\t"; cout << endl; } // liberiamo le risorse delete res; delete stmt; connection->close(); delete connection; } catch(sql::SQLException& e) { cout << e.what() << endl; } }
Otterremo come output:
>> Presi 5 record << cod name blabla4 Aldo blabla1 Antonio blabla5 Giovanni blabla3 Marco blabla2 Mario
Modifichiamo il nostro esempio per mostrare l’utilizzo della classe PreparedStatement:
#include <string> #include <iostream> #include <cppconn/driver.h> #include <cppconn/connection.h> #include <cppconn/exception.h> #include <cppconn/prepared_statement.h> #include <cppconn/resultset.h> #include <cppconn/resultset_metadata.h> using namespace std; const string user = "root"; const string passwd = "secret"; const string database = "test"; const string dbhost = "tcp://127.0.0.1:3306"; int main() { sql::Driver* driver; sql::Connection* connection; sql::PreparedStatement* stmt; sql::ResultSet* res; sql::ResultSetMetaData* res_md; // query parametrica string query = "SELECT cod, name from persone where name = ?"; try { driver = get_driver_instance(); connection = driver->connect(dbhost, user, passwd); connection->setSchema(database); string name; while(1) { cout << "[nome (quit per terminare)]<< "; getline(cin, name); if(name == "quit") break; // preparo lo statement stmt = connection->prepareStatement(query); // setto il valore stmt->setString(1, name); res = stmt->executeQuery(); res_md = res->getMetaData(); if(res->rowsCount() == 0) { cout << endl << endl << ">> Nessun record trovato <<" << endl << endl; continue; } cout << endl << endl; for(int i = 1; i <= res_md->getColumnCount(); i++) cout << res_md->getColumnLabel(i) << "\t\t"; cout << endl << endl; while(res->next()) { for(int i = 1; i <= res_md->getColumnCount(); i++) cout << res->getString(i) << "\t\t"; cout << endl; } cout << endl << endl; } delete res; delete stmt; connection->close(); delete connection; } catch(sql::SQLException& e) { cout << e.what() << endl; } }
Dopo esser stato eseguito, il programma chiederà in input un nome e lo cercherà all’interno del database, fino a che non digiteremo quit.
L’uso di un PreparedStatement rende la costruzione delle query più elegante e flessibile, oltre ad evitare le classiche SQL Injection.