Avanti
Indietro
Indice
Se si vogliono scrivere applicazioni portabili su altri database, si eviti di
usare direttamente questo modulo. _mysql fornisce un'interfaccia che
perlopiù implementa l'API C di MySQL. Per maggiori informazioni si
consulti la documentazione MySQL. La documentazione di questo modulo è
scarna di proposito, poiché nella gran parte dei casi è molto
meglio usare il modulo
MySQLdb
. Se davvero si ha bisogno di usarlo,
si faccia riferimento ai doc standard di MySQL e li si adatti secondo
necessità.
L'API C di MySQL è stata incapsulata in stile orientato agli oggetti. Le
uniche strutture dati MySQL implementate sono i tipi MYSQL (per gestire
le connessioni al database) e MYSQL_RES (per gestire i risultati). In
generale, qualunque funzione che prende MYSQL *mysql come argomento
diventa un metodo dell'oggetto connessione e qualunque funzione che prende
MYSQL_RES *result come argomento è un metodo dell'oggetto
risultato. Le funzioni che non richiedeno alcuna struttura dati di MySQL sono
implementate come funzioni nel modulo. Le funzioni che richiedono strutture dati
di MySQL diverse dalle due sopra in genere non sono implementate. Le funzioni
deprecate non sono implementate. In tutti i casi il prefisso mysql_
è stato eliminato. La maggior parte dei metodi conn elencati sono
anche disponibili come metodi dell'oggetto Connessione di MySQLdb. Il loro uso
impedisce la portabilità.
C API | _mysql |
mysql_affected_rows() | conn.affected_rows() |
mysql_close() | conn.close() |
mysql_connect() | _mysql.connect() |
mysql_data_seek() | result.data_seek() |
mysql_debug() | _mysql.debug() |
mysql_dump_debug_info | conn.dump_debug_info() |
mysql_escape_string() | _mysql.escape_string() |
mysql_fetch_row() | result.fetch_row() |
mysql_get_client_info() | _mysql.get_client_info() |
mysql_get_host_info() | conn.get_host_info() |
mysql_get_proto_info() | conn.get_proto_info() |
mysql_get_server_info() | conn.get_server_info() |
mysql_info() | conn.info() |
mysql_insert_id() | conn.insert_id() |
mysql_num_fields() | result.num_fields() |
mysql_num_rows() | result.num_rows() |
mysql_options() | _mysql.connect() |
mysql_ping() | conn.ping() |
mysql_query() | conn.query() |
mysql_real_connect() | _mysql.connect() |
mysql_real_query() | conn.query() |
mysql_real_escape_string() | conn.escape_string() |
mysql_row_seek() | result.row_seek() |
mysql_row_tell() | result.row_tell() |
mysql_select_db() | conn.select_db() |
mysql_stat() | conn.stat() |
mysql_store_result() | conn.store_result() |
mysql_thread_id() | conn.thread_id() |
mysql_use_result() | conn.use_result() |
CLIENT_* | MySQLdb.constants.CLIENT.* |
CR_* | MySQLdb.constants.CR.* |
ER_* | MySQLdb.constants.ER.* |
FIELD_TYPE_* | MySQLdb.constants.FIELD_TYPE.* |
FLAG_* | MySQLdb.constants.FLAG.*
Mappatura delle funzioni C dell'API MySQL
|
Va bene, volete usare comunque _mysql . Ecco degli esempi.
La connessione più semplice al database è:
import _mysql
db=_mysql.connect()
Così si crea una connessione al server MySQL in esecuzione sulla macchina
locale usando i socket UNIX standard, il proprio nome di login (preso dalla
variabile di ambiente USER), nessuna password. E non USA un database. Magari
funzionerà, soprattutto se si ha impostato un file di configurazione, per
dire ~/.my.cnf [notare che si sta parlando dell'uso su *ix NdT], ma
è probabile che sia necessario fornire maggiori informazioni.
db=_mysql.connect("localhost","joebob","moonpie","thangs")
Questo crea una connessione al server MySQL in esecuzione sulla macchina locale
usando TCP sulla porta standard (3306), il nome utente è
"joebob", la password "moonpie" e si lavora inizialmente sul database "thangs".
Non abbiamo nemmeno iniziato a parlare di tutti i parametri che connect()
può ricevere e si noterà che se si usano parametri posizionali si
è costretti di fatto a usare TCP, perdendo parecchio in velocità
rispetto ai socket UNIX. (Ovviamente si deve usare comunque TCP se si tratta di
un host remoto). Per questa ragione preferisco usare i parametri a parola chiave:
db=_mysql.connect(host="localhost",user="joebob",
passwd="moonpie",db="thangs")
Questo fa esattamente la stessa cosa dell'esempio precedente, ma è certo
più facile da leggere. Ora se si volessero usare proprio i socket UNIX e
il nome di login fosse "joebob", si potrebbe abbreviare il tutto con:
db=_mysql.connect(passwd="moonpie",db="thangs")
Ci sono alcuni altri parametri che si potrebbero usare. Per la maggior parte non
sono necessari, tranne uno. Pel resto si legga la documentazione inclusa nel
modulo. Il modulo pydoc di Python 2.1 è davvero utile a questo scopo.
Dunque, ora abbiamo una connessione aperta db e vogliamo sottoporre una
interrogazione. Bene, non ci sono cursori in MySQL, nemmeno la sostituzione
di parametri, quindi tocca passare un'intera interrogazione come stringa a
db.query() :
db.query("""SELECT spam, eggs, sausage FROM breakfast
WHERE price < 5""")
Questo non restituisce alcun valore, ma possono venir sollevate eccezioni. Le
eccezioni sono definite in un modulo separato, _mysql_exceptions , ma
_mysql le esporta. Si leggano le Specifiche API DB
v.2.0 per sapere quali siano, oppure si usi MySQLError , che cattura
qualunque cosa.
A questo punto l'interrogazione è stata eseguita e si vogliono ricevere
i risultati. Ci sono due opzioni:
r=db.store_result()
# ...oppure...
r=db.use_result()
Entrambi i metodi restituiscono un oggetto Risultato. Qual'è la differenza?
store_result() restituisce immediatamente l'intero risultato al client. In
caso esso sia molto ampio, questo comportamento potrebbe causare dei problemi. Un
modo per evitarlo è aggiungere una clausola LIMIT all'interrogazione,
per limitare il numero di righe restituite. L'altro è usare use_result() ,
che conserva il risultato nel server e lo invia riga per riga quando lo si preleva.
Tutto ciò comunque pesa parecchio sulle risorse del server e sulla
connessione: non si possono fare altre interrogazioni fino a che non si sono
recuperate tutte le righe. In genere raccomando di usare store_result() a
meno che il risultato dell'interrogazione non sia davvero di dimensioni enormi e
che per qualche ragione non si possa usare LIMIT .
Ora, per ottenere effettivamente i risultati reali:
>>> r.fetch_row()
(('3','2','0'),)
Potrebbe sembrare un po' insolito. La prima cosa da sapere è che
fetch_row() accetta alcuni parametri aggiuntivi. Il primo dice quante
righe (maxrows ) dovrebbero venir restituite. Per default viene restituita
una riga. Potrebbero venir restituite meno righe di quanto richiesto, ma mai
di più. Impostando maxrows=0 vengono restituite tutte le righe del
risultato. In caso si riceva indietro una tupla vuota, significa che si sono
esaurite le righe.
Il secondo parametro (how ) dice come dovrebbe venir rappresentata la riga.
Per default è zero, il che significa che va restituita come tupla.
how=1 significa che va restituita come dizionario, dove le chiavi sono
i nomi delle colonne, o tabella.colonna se ci sono due colonne con lo
stesso nome (per dire nel caso di un join). how=2 significa lo stesso di
how=1 eccetto che le chiavi sono sempre tabella.colonna ; serve
per compatibilità con il vecchio modulo Mysqldb .
Bene, allora perché abbiamo ottenuto una tupla di un solo elemento con
dentro una tupla? Perché abbiamo implicitamente richiesto una sola riga,
dato che non abbiamo specificato maxrows .
L'altra cosa singolare è: assumendo che si tratti di colonne numeriche,
perché vengono restituite come stringhe? Perché MySQL restituisce
tutti i dati come stringhe e si aspetta che la conversione venga fatta in proprio.
Questa rischia di essere una vera fregatura, ma in effetti lo può fare
_mysql . (E MySQLdb lo fa). Per ottenere la conversione automatica di
tipi è necessario creare un dizionario apposito e passarlo a connect()
come parametro a parola chiave conv .
Le chiavi di conv dovrebbero essere i tipi delle colonne MySQL, che nell'API
C sono FIELD_TYPE_* . Si possono ottenere tali valori con:
from MySQLdb.constants import FIELD_TYPE
Per default qualsiasi tipo di colonna che non viene trovato in conv è
restituito come stringa, il che funziona bene per un sacco di roba. Per i nostri
scopi vogliamo probabilmente questo:
my_conv = { FIELD_TYPE.LONG: int }
Ciò significa che se c'è un FIELD_TYPE_LONG verrà
chiamata su di esso la funzione primitiva int() . Si noti che
FIELD_TYPE_LONG è una colonna INTEGER , che corrisponde a un
long C, che è anche il tipo usato per i normali interi Python.
Ma attenzione: se si tratta di una colonna UNSIGNED INTEGER potrebbero
capitare degli overflow. Per questa ragione MySQLdb usa in realtà
dei long() per fare la conversione. Per ora ignoreremo questo potenziale
problema.
Quindi, se si usa db=_mysql.connect(conv=my_conv...) i risultati verranno
restituiti come ((3, 2, 0),) , che è quanto ci si aspetterebbe.
Avanti
Indietro
Indice
|